public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Enable vector instruction debugging for AIX
@ 2022-10-13 10:52 Aditya Kamath1
  2022-10-13 10:52 ` Aditya Kamath1
  2022-10-14 12:41 ` Ulrich Weigand
  0 siblings, 2 replies; 18+ messages in thread
From: Aditya Kamath1 @ 2022-10-13 10:52 UTC (permalink / raw)
  To: Aditya Kamath1 via Gdb-patches, Ulrich Weigand, simark
  Cc: Sangamesh Mallayya, Aditya Kamath1

[-- Attachment #1: Type: text/plain, Size: 3247 bytes --]

Hi all,

Brief Introduction:- Vector registers are an extension to the POWERPC processor architecture in order to support vector and matrix mathematical functions. This is to improve graphics and multimedia. For example, the vector ALU SIMD- style arithmetic unit where a single instruction performs the same operation on all the data elements of each vector.


The problem:- While a user finds bugs in applications which uses vector instructions, they would like to debug vector registers or set vector registers to a particular value to figure it out. Currently in AIX, we have not enabled vector instruction debugging. This patch is used to enable vector instruction debugging.

Please find attached the patch. [See 0001-PATCH-Enable-Vector-support-for-AIX.patch]

A sample program is as shown below:-


#include <stdio.h>

int main () {

vector int Arr1[5] = {

  { 1, 2, 3, 4 },

  { 11, 22, 33, 44 },

  { 111, 222, 333, 444 },

  { 1111, 2222, 3333, 4444 },

  { 11111, 22222, 33333, 44444 }

};

vector int Arr2[5] = {

  { 1, 2, 3, 4 },

  { 11, 22, 33, 44 },

  { 111, 222, 333, 444 },

  { 1111, 2222, 3333, 4444 },

  { 11111, 22222, 33333, 44444 }

};

vector int Arr3[5] = {

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 }

};

        printf("Adding Arrays\n");

        Arr3[1] = Arr1[2] + Arr2[3];

        printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);

        return 0;

}


The output expected is as follows:-


(gdb) b main

Breakpoint 1 at 0x1000052c: file /home/XYZ/gdb_tests/vector_lab_test.c, line 3.

(gdb) r

Starting program: /home/XYZ/gdb_tests/vector_lab_test


Breakpoint 1, main () at /home/XYZ/gdb_tests/vector_lab_test.c:3

3       vector int Arr1[5] = {

(gdb) n

10      vector int Arr2[5] = {

(gdb) n

17      vector int Arr3[5] = {

(gdb) n

24              printf("Adding Arrays\n");

(gdb) n

Adding Arrays

25              Arr3[1] = Arr1[2] + Arr2[3];

(gdb) n

26              printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);

(gdb) info reg vr0

vr0            {uint128 = 0x4c60000098c00000e5200001318, v4_float = {0x4c6, 0x98c, 0xe52, 0x1318}, v4_int32 = {0x4c6, 0x98c, 0xe52, 0x1318}, v8_int16 = {0x0, 0x4c6, 0x0, 0x98c, 0x0, 0xe52, 0x0, 0x1318}, v16_int8 = {0x0, 0x0, 0x4, 0xc6, 0x0, 0x0, 0x9, 0x8c, 0x0, 0x0, 0xe, 0x52, 0x0, 0x0, 0x13, 0x18}}

(gdb) set $vr0.v4_int32[3] = 1

(gdb) info reg vr0

vr0            {uint128 = 0x4c60000098c00000e5200000001, v4_float = {0x4c6, 0x98c, 0xe52, 0x1}, v4_int32 = {0x4c6, 0x98c, 0xe52, 0x1}, v8_int16 = {0x0, 0x4c6, 0x0, 0x98c, 0x0, 0xe52, 0x0, 0x1}, v16_int8 = {0x0, 0x0, 0x4, 0xc6, 0x0, 0x0, 0x9, 0x8c, 0x0, 0x0, 0xe, 0x52, 0x0, 0x0, 0x0, 0x1}}

(gdb)

-------------------------------------------------------------------------


Kindly note in AIX unless and until a debugee uses vector registers the debugger cannot set or get the same.

Kindly let me know if this patch works. If yes, kindly push it else kindly give me feedback for changes.

Have a nice day ahead.

Thanks and regards,
Aditya.

[-- Attachment #2: 0001-PATCH-Enable-Vector-support-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26055 bytes --]

From e1db88b16f7e78cd8312eeb729859298cc8d0eab Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Thu, 13 Oct 2022 05:21:36 -0500
Subject: [PATCH] Enable vector instruction debugging for AIX

---
 gdb/aix-thread.c      | 114 +++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 220 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-tdep.c | 213 +++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-tdep.c     |  67 ++++++-------
 4 files changed, 568 insertions(+), 46 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 57e5756e144..15400f5b90d 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -1347,11 +1347,75 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	  supply_sprs32 (regcache, sprs32.pt_iar, sprs32.pt_msr, sprs32.pt_cr,
 			 sprs32.pt_lr, sprs32.pt_ctr, sprs32.pt_xer,
 			 sprs32.pt_fpscr);
-
-	  if (tdep->ppc_mq_regnum >= 0)
-	    regcache->raw_supply (tdep->ppc_mq_regnum, (char *) &sprs32.pt_mq);
 	}
+     }
+  /* vector registers */
+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
+  {
+    int ret = 0;
+    int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+    __vmx_context_t vmx;
+    memset(&vmx, 0, sizeof(__vmx_context_t));
+    if (__power_vmx())
+    {
+       ret = ptrace64 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+       if (ret < 0)
+       {
+         if (errno == ENXIO)
+           return;
+         perror_with_name (_("Unable to fetch AltiVec registers"));
+       }
+       for (i = 0; i < num_of_vrregs; i++)
+         regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+    }
+  }
+
+  /* vsx registers */
+  if (tdep->ppc_vsr0_upper_regnum != -1 && regno >= tdep->ppc_vsr0_upper_regnum)
+  {
+    __vsx_context_t vsx;
+    memset(&vsx, 0, sizeof(__vsx_context_t));
+    if (__power_vsx())
+    {
+      int ret = 0;
+      ret = ptrace64 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      if (ret < 0)
+      {
+        if (errno == ENXIO)
+          return;
+        perror_with_name (_("Unable to fetch VSX registers"));
+      }
+    for (i = 0; i < ppc_num_vshrs; i++)
+      regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
     }
+  } 
+}
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  int regno;
+
+  for (regno = 0; regno < num_of_vrregs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+                                 &(vmx->__vr[0]) + regno);
+}
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from the
@@ -1692,6 +1756,50 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
+    {
+      int ret = 0;
+      __vmx_context_t vmx;
+      memset(&vmx, 0, sizeof(__vmx_context_t));
+      if (__power_vmx())
+      {
+         ret = ptrace64 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+         if (ret < 0)
+         {
+           if (errno == ENXIO)
+           {
+             warning (_("Unable to fetch AltiVec registers."));
+             return;
+           }
+           fill_altivec(regcache, &vmx);
+           ret = ptrace64 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+           if (ret < 0)
+             perror_with_name (_("Unable to store AltiVec register."));
+       }
+     }
+   }
+   /* vmx registers */
+   if (tdep->ppc_vsr0_upper_regnum != -1 && regno >= tdep->ppc_vsr0_upper_regnum)
+   {
+     __vsx_context_t vsx;
+     memset(&vsx, 0, sizeof(__vsx_context_t));
+     if (__power_vsx())
+     {
+        int ret =  ptrace64 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch VSX registers."));
+            return;
+          }
+        }
+        fill_vsx (regcache, &vsx);
+        ret = ptrace64 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          perror_with_name (_("Unable to store VSX register."));
+    }
+  }
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index cb141427696..e989a9a6739 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -54,6 +54,19 @@
 #include <sys/ldr.h>
 #include <sys/systemcfg.h>
 
+#include "gdbthread.h"
+#include <sys/context.h>
+#include <sys/pthdebug.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
+int have_ptrace_getvrregs = 1;
+
+int have_ptrace_getsetvsxregs = 1;
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -91,6 +104,8 @@ class rs6000_nat_target final : public inf_ptrace_target
 
   ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override
@@ -107,6 +122,82 @@ class rs6000_nat_target final : public inf_ptrace_target
 
 static rs6000_nat_target the_rs6000_nat_target;
 
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx()) 
+  {
+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         /* have_ptrace_getsetvsxregs = 0; */
+         warning (_("Unable to fetch VSX registers."));
+         return;
+       }
+    }
+  }
+  regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                       regno - tdep->ppc_vsr0_upper_regnum);
+
+  ret = ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store VSX register."));
+}
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())  
+  {
+    ret = ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         /* have_ptrace_getvrregs = 0; */
+         warning (_("Unable to fetch AltiVec registers."));
+         return;
+       }
+    }
+  }   
+
+  regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                - tdep->ppc_vr0_regnum);
+
+  ret = ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+  if (ret < 0)
+     perror_with_name (_("Unable to store AltiVec register."));
+
+}
+
 /* Given REGNO, a gdb register number, return the corresponding
    number suitable for use as a ptrace() parameter.  Return -1 if
    there's no suitable mapping.  Also, set the int pointed to by
@@ -264,6 +355,17 @@ store_register (struct regcache *regcache, int regno)
 
   nr = regmap (gdbarch, regno, &isfloat);
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   /* Floating-point registers.  */
   if (isfloat)
     rs6000_ptrace32 (PT_WRITE_FPR, pid, addr, nr, 0);
@@ -305,6 +407,98 @@ store_register (struct regcache *regcache, int regno)
     }
 }
 
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  int ret;
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())  
+  {
+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    if (ret < 0)
+    {
+       /* Just fill with 0 zero instead of error return */
+       #if 0
+         if (errno == ENXIO)
+         {
+           have_ptrace_getsetvsxregs = 0;
+           return;
+           perror_with_name (_("Unable to fetch VSX registers"));
+         }
+       #endif
+    }
+  }
+  supply_vsxregset_aix (regcache, &vsx);
+}
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+}
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  int ret;
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {  
+    ret = ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       /* Just fill with 0 zero instead of error return */
+       #if 0
+        if (errno == ENXIO)
+         {
+           have_ptrace_getvrregs = 0;
+           return;
+           perror_with_name (_("Unable to fetch AltiVec registers"));
+         }
+       #endif
+    }
+  }   
+  supply_vrregset_aix (regcache, &vmx);
+}
+
+
 /* Read from the inferior all registers if REGNO == -1 and just register
    REGNO otherwise.  */
 
@@ -312,10 +506,6 @@ void
 rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = regcache->arch ();
-  if (regno != -1)
-    fetch_register (regcache, regno);
-
-  else
     {
       ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
 
@@ -331,7 +521,18 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
       if (tdep->ppc_fp0_regnum >= 0)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
-
+      
+      if (have_ptrace_getvrregs)
+        if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) 
+        {
+           fetch_altivec_registers_aix (regcache);
+        }
+
+     if (have_ptrace_getsetvsxregs)
+         if (tdep->ppc_vsr0_upper_regnum != -1)
+          {
+            fetch_vsx_registers_aix (regcache);
+          }
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -346,6 +547,15 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+      return tdesc_powerpc_vsx64;
+   else
+      return tdesc_powerpc_vsx32;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index d47974b51d1..67ae8a6a54a 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,22 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+   
+  
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -145,7 +161,7 @@ aix_sighandle_frame_prev_register (frame_info_ptr this_frame,
 
 static int
 aix_sighandle_frame_sniffer (const struct frame_unwind *self,
-			     frame_info_ptr this_frame,
+			     frame_info_ptr this_frame, 
 			     void **this_prologue_cache)
 {
   CORE_ADDR pc = get_frame_pc (this_frame);
@@ -237,6 +253,190 @@ rs6000_aix_collect_regset (const struct regset *regset,
   ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
 }
 
+/* Return non-zero if the architecture described by GDBARCH has
+   VSX registers (vsr0 --- vsr63).  */
+static int
+rs6000_aix_vsx_support_p (struct gdbarch *gdbarch)
+{
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  return tdep->ppc_vsr0_regnum >= 0;
+}
+
+/* Return non-zero if the architecture described by GDBARCH has
+   Altivec registers (vr0 --- vr31, vrsave and vscr).  */
+static int
+rs6000_aix_altivec_support_p (struct gdbarch *gdbarch)
+{
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  return (tdep->ppc_vr0_regnum >= 0
+   && tdep->ppc_vrsave_regnum >= 0);
+}
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+                  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                  int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                     int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+
+  if (!rs6000_aix_altivec_support_p (gdbarch))
+    return;
+  
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+    && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+  
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                     int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+
+  if (!rs6000_aix_vsx_support_p (gdbarch))
+    return;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum;
+     i < tdep->ppc_vsr0_upper_regnum + 32;
+                           i++, offset++)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset * 8, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                      const struct regcache *regcache,
+                      int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+
+  if (!rs6000_aix_vsx_support_p (gdbarch))
+    return;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vsr0_upper_regnum;
+     i < tdep->ppc_vsr0_upper_regnum + 32;
+                                     i++)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+} 
+
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                      const struct regcache *regcache,
+                      int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  if (!rs6000_aix_altivec_support_p (gdbarch))
+    return;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix32_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix32_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
 /* AIX register set.  */
 
 static const struct regset rs6000_aix32_regset =
@@ -262,10 +462,19 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+   
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+ 
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx", cb_data);    
 }
 
 
@@ -351,7 +560,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
       arg = args[argno];
       type = check_typedef (value_type (arg));
-      len = type->length ();
+      len = type->length (); 
 
       if (type->code () == TYPE_CODE_FLT)
 	{
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 8b6d666bbe7..6e8ffc5fb0d 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
       /* 001110 00000 00000 iiii iiii iiii iiii  */
       /* 001110 01110 00000 iiii iiii iiii iiii  */
       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM */
-	       || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM */
+	       || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM */
+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4, SIMM */ 
 	{
 	  if ((op & 0xffff0000) == 0x38000000)
 	    r0_contains_arg = 0;
@@ -1986,24 +1987,21 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 	}
       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */      
       /* 011111 sssss 11111 00000 00111001110 */
-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
-	{
-	  if (pc == (li_found_pc + 4))
-	    {
-	      vr_reg = GET_SRC_REG (op);
-	      /* If this is the first vector reg to be saved, or if
-		 it has a lower number than others previously seen,
-		 reupdate the frame info.  */
-	      if (fdata->saved_vr == -1 || fdata->saved_vr > vr_reg)
-		{
-		  fdata->saved_vr = vr_reg;
-		  fdata->vr_offset = vr_saved_offset + offset;
-		}
-	      vr_saved_offset = -1;
-	      vr_reg = -1;
-	      li_found_pc = 0;
-	    }
-	}
+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1, r5 */
+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1, r5 */
+               || (op & 0xfc1ff000) == 0x7c012000)   
+      {
+        vr_reg = GET_SRC_REG (op);
+        /* If this is the first vector reg to be saved, or if
+       	   it has a lower number than others previously seen,
+       	   reupdate the frame info.  */
+        fdata->saved_vr = vr_reg;
+        fdata->vr_offset = vr_saved_offset;
+        vr_saved_offset = -1;
+        vr_reg = -1;
+        li_found_pc = 0;
+      }
       /* End AltiVec related instructions.  */
 
       /* Start BookE related instructions.  */
@@ -2665,8 +2663,8 @@ rs6000_convert_register_p (struct gdbarch *gdbarch, int regnum,
 	  && regnum >= tdep->ppc_fp0_regnum
 	  && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs
 	  && type->code () == TYPE_CODE_FLT
-	  && (type->length ()
-	      != builtin_type (gdbarch)->builtin_double->length ()));
+          && (type->length ()
+              != builtin_type (gdbarch)->builtin_double->length ()));
 }
 
 static int
@@ -3466,7 +3464,7 @@ struct ppc_variant
     unsigned long mach;
 
     /* Target description for this variant.  */
-    const struct target_desc **tdesc;
+    struct target_desc **tdesc;
   };
 
 static struct ppc_variant variants[] =
@@ -3474,7 +3472,7 @@ static struct ppc_variant variants[] =
   {"powerpc", "PowerPC user-level", bfd_arch_powerpc,
    bfd_mach_ppc, &tdesc_powerpc_altivec32},
   {"power", "POWER user-level", bfd_arch_rs6000,
-   bfd_mach_rs6k, &tdesc_rs6000},
+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},
   {"403", "IBM PowerPC 403", bfd_arch_powerpc,
    bfd_mach_ppc_403, &tdesc_powerpc_403},
   {"405", "IBM PowerPC 405", bfd_arch_powerpc,
@@ -3504,7 +3502,7 @@ static struct ppc_variant variants[] =
   {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc,
    bfd_mach_ppc64, &tdesc_powerpc_altivec64},
   {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
-   bfd_mach_ppc_620, &tdesc_powerpc_64},
+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},
   {"630", "Motorola PowerPC 630", bfd_arch_powerpc,
    bfd_mach_ppc_630, &tdesc_powerpc_64},
   {"a35", "PowerPC A35", bfd_arch_powerpc,
@@ -3680,18 +3678,15 @@ rs6000_frame_cache (frame_info_ptr this_frame, void **this_cache)
   /* if != -1, fdata.saved_vr is the smallest number of saved_vr.
      All vr's from saved_vr to vr31 are saved.  */
   if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
-    {
-      if (fdata.saved_vr >= 0)
-	{
-	  int i;
-	  CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
-	  for (i = fdata.saved_vr; i < 32; i++)
-	    {
-	      cache->saved_regs[tdep->ppc_vr0_regnum + i].set_addr (vr_addr);
-	      vr_addr += register_size (gdbarch, tdep->ppc_vr0_regnum);
-	    }
-	}
-    }
+  {
+    int i;
+    CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
+    for (i = 0; i < 66; i++)
+    {
+      cache->saved_regs[tdep->ppc_vsr0_upper_regnum + i].set_addr (vr_addr);
+      vr_addr += register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+    } 
+  } 
 
   /* if != -1, fdata.saved_ev is the smallest number of saved_ev.
      All vr's from saved_ev to ev31 are saved. ?????  */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] Enable vector instruction debugging for AIX
  2022-10-13 10:52 [PATCH] Enable vector instruction debugging for AIX Aditya Kamath1
@ 2022-10-13 10:52 ` Aditya Kamath1
  2022-10-14 12:41 ` Ulrich Weigand
  1 sibling, 0 replies; 18+ messages in thread
From: Aditya Kamath1 @ 2022-10-13 10:52 UTC (permalink / raw)
  To: Aditya Kamath1 via Gdb-patches, Ulrich Weigand, simark
  Cc: Sangamesh Mallayya, Aditya Kamath1


[-- Attachment #1.1: Type: text/plain, Size: 3247 bytes --]

Hi all,

Brief Introduction:- Vector registers are an extension to the POWERPC processor architecture in order to support vector and matrix mathematical functions. This is to improve graphics and multimedia. For example, the vector ALU SIMD- style arithmetic unit where a single instruction performs the same operation on all the data elements of each vector.


The problem:- While a user finds bugs in applications which uses vector instructions, they would like to debug vector registers or set vector registers to a particular value to figure it out. Currently in AIX, we have not enabled vector instruction debugging. This patch is used to enable vector instruction debugging.

Please find attached the patch. [See 0001-PATCH-Enable-Vector-support-for-AIX.patch]

A sample program is as shown below:-


#include <stdio.h>

int main () {

vector int Arr1[5] = {

  { 1, 2, 3, 4 },

  { 11, 22, 33, 44 },

  { 111, 222, 333, 444 },

  { 1111, 2222, 3333, 4444 },

  { 11111, 22222, 33333, 44444 }

};

vector int Arr2[5] = {

  { 1, 2, 3, 4 },

  { 11, 22, 33, 44 },

  { 111, 222, 333, 444 },

  { 1111, 2222, 3333, 4444 },

  { 11111, 22222, 33333, 44444 }

};

vector int Arr3[5] = {

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 },

  { 0, 0, 0, 0 }

};

        printf("Adding Arrays\n");

        Arr3[1] = Arr1[2] + Arr2[3];

        printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);

        return 0;

}


The output expected is as follows:-


(gdb) b main

Breakpoint 1 at 0x1000052c: file /home/XYZ/gdb_tests/vector_lab_test.c, line 3.

(gdb) r

Starting program: /home/XYZ/gdb_tests/vector_lab_test


Breakpoint 1, main () at /home/XYZ/gdb_tests/vector_lab_test.c:3

3       vector int Arr1[5] = {

(gdb) n

10      vector int Arr2[5] = {

(gdb) n

17      vector int Arr3[5] = {

(gdb) n

24              printf("Adding Arrays\n");

(gdb) n

Adding Arrays

25              Arr3[1] = Arr1[2] + Arr2[3];

(gdb) n

26              printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);

(gdb) info reg vr0

vr0            {uint128 = 0x4c60000098c00000e5200001318, v4_float = {0x4c6, 0x98c, 0xe52, 0x1318}, v4_int32 = {0x4c6, 0x98c, 0xe52, 0x1318}, v8_int16 = {0x0, 0x4c6, 0x0, 0x98c, 0x0, 0xe52, 0x0, 0x1318}, v16_int8 = {0x0, 0x0, 0x4, 0xc6, 0x0, 0x0, 0x9, 0x8c, 0x0, 0x0, 0xe, 0x52, 0x0, 0x0, 0x13, 0x18}}

(gdb) set $vr0.v4_int32[3] = 1

(gdb) info reg vr0

vr0            {uint128 = 0x4c60000098c00000e5200000001, v4_float = {0x4c6, 0x98c, 0xe52, 0x1}, v4_int32 = {0x4c6, 0x98c, 0xe52, 0x1}, v8_int16 = {0x0, 0x4c6, 0x0, 0x98c, 0x0, 0xe52, 0x0, 0x1}, v16_int8 = {0x0, 0x0, 0x4, 0xc6, 0x0, 0x0, 0x9, 0x8c, 0x0, 0x0, 0xe, 0x52, 0x0, 0x0, 0x0, 0x1}}

(gdb)

-------------------------------------------------------------------------


Kindly note in AIX unless and until a debugee uses vector registers the debugger cannot set or get the same.

Kindly let me know if this patch works. If yes, kindly push it else kindly give me feedback for changes.

Have a nice day ahead.

Thanks and regards,
Aditya.

[-- Attachment #2: 0001-PATCH-Enable-Vector-support-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26055 bytes --]

From e1db88b16f7e78cd8312eeb729859298cc8d0eab Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Thu, 13 Oct 2022 05:21:36 -0500
Subject: [PATCH] Enable vector instruction debugging for AIX

---
 gdb/aix-thread.c      | 114 +++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 220 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-tdep.c | 213 +++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-tdep.c     |  67 ++++++-------
 4 files changed, 568 insertions(+), 46 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 57e5756e144..15400f5b90d 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -1347,11 +1347,75 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	  supply_sprs32 (regcache, sprs32.pt_iar, sprs32.pt_msr, sprs32.pt_cr,
 			 sprs32.pt_lr, sprs32.pt_ctr, sprs32.pt_xer,
 			 sprs32.pt_fpscr);
-
-	  if (tdep->ppc_mq_regnum >= 0)
-	    regcache->raw_supply (tdep->ppc_mq_regnum, (char *) &sprs32.pt_mq);
 	}
+     }
+  /* vector registers */
+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
+  {
+    int ret = 0;
+    int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+    __vmx_context_t vmx;
+    memset(&vmx, 0, sizeof(__vmx_context_t));
+    if (__power_vmx())
+    {
+       ret = ptrace64 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+       if (ret < 0)
+       {
+         if (errno == ENXIO)
+           return;
+         perror_with_name (_("Unable to fetch AltiVec registers"));
+       }
+       for (i = 0; i < num_of_vrregs; i++)
+         regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+    }
+  }
+
+  /* vsx registers */
+  if (tdep->ppc_vsr0_upper_regnum != -1 && regno >= tdep->ppc_vsr0_upper_regnum)
+  {
+    __vsx_context_t vsx;
+    memset(&vsx, 0, sizeof(__vsx_context_t));
+    if (__power_vsx())
+    {
+      int ret = 0;
+      ret = ptrace64 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      if (ret < 0)
+      {
+        if (errno == ENXIO)
+          return;
+        perror_with_name (_("Unable to fetch VSX registers"));
+      }
+    for (i = 0; i < ppc_num_vshrs; i++)
+      regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
     }
+  } 
+}
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  int regno;
+
+  for (regno = 0; regno < num_of_vrregs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+                                 &(vmx->__vr[0]) + regno);
+}
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from the
@@ -1692,6 +1756,50 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
+    {
+      int ret = 0;
+      __vmx_context_t vmx;
+      memset(&vmx, 0, sizeof(__vmx_context_t));
+      if (__power_vmx())
+      {
+         ret = ptrace64 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+         if (ret < 0)
+         {
+           if (errno == ENXIO)
+           {
+             warning (_("Unable to fetch AltiVec registers."));
+             return;
+           }
+           fill_altivec(regcache, &vmx);
+           ret = ptrace64 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+           if (ret < 0)
+             perror_with_name (_("Unable to store AltiVec register."));
+       }
+     }
+   }
+   /* vmx registers */
+   if (tdep->ppc_vsr0_upper_regnum != -1 && regno >= tdep->ppc_vsr0_upper_regnum)
+   {
+     __vsx_context_t vsx;
+     memset(&vsx, 0, sizeof(__vsx_context_t));
+     if (__power_vsx())
+     {
+        int ret =  ptrace64 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch VSX registers."));
+            return;
+          }
+        }
+        fill_vsx (regcache, &vsx);
+        ret = ptrace64 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          perror_with_name (_("Unable to store VSX register."));
+    }
+  }
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index cb141427696..e989a9a6739 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -54,6 +54,19 @@
 #include <sys/ldr.h>
 #include <sys/systemcfg.h>
 
+#include "gdbthread.h"
+#include <sys/context.h>
+#include <sys/pthdebug.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
+int have_ptrace_getvrregs = 1;
+
+int have_ptrace_getsetvsxregs = 1;
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -91,6 +104,8 @@ class rs6000_nat_target final : public inf_ptrace_target
 
   ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override
@@ -107,6 +122,82 @@ class rs6000_nat_target final : public inf_ptrace_target
 
 static rs6000_nat_target the_rs6000_nat_target;
 
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx()) 
+  {
+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         /* have_ptrace_getsetvsxregs = 0; */
+         warning (_("Unable to fetch VSX registers."));
+         return;
+       }
+    }
+  }
+  regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                       regno - tdep->ppc_vsr0_upper_regnum);
+
+  ret = ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store VSX register."));
+}
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())  
+  {
+    ret = ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         /* have_ptrace_getvrregs = 0; */
+         warning (_("Unable to fetch AltiVec registers."));
+         return;
+       }
+    }
+  }   
+
+  regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                - tdep->ppc_vr0_regnum);
+
+  ret = ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+  if (ret < 0)
+     perror_with_name (_("Unable to store AltiVec register."));
+
+}
+
 /* Given REGNO, a gdb register number, return the corresponding
    number suitable for use as a ptrace() parameter.  Return -1 if
    there's no suitable mapping.  Also, set the int pointed to by
@@ -264,6 +355,17 @@ store_register (struct regcache *regcache, int regno)
 
   nr = regmap (gdbarch, regno, &isfloat);
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   /* Floating-point registers.  */
   if (isfloat)
     rs6000_ptrace32 (PT_WRITE_FPR, pid, addr, nr, 0);
@@ -305,6 +407,98 @@ store_register (struct regcache *regcache, int regno)
     }
 }
 
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  int ret;
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())  
+  {
+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    if (ret < 0)
+    {
+       /* Just fill with 0 zero instead of error return */
+       #if 0
+         if (errno == ENXIO)
+         {
+           have_ptrace_getsetvsxregs = 0;
+           return;
+           perror_with_name (_("Unable to fetch VSX registers"));
+         }
+       #endif
+    }
+  }
+  supply_vsxregset_aix (regcache, &vsx);
+}
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+}
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  int ret;
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {  
+    ret = ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       /* Just fill with 0 zero instead of error return */
+       #if 0
+        if (errno == ENXIO)
+         {
+           have_ptrace_getvrregs = 0;
+           return;
+           perror_with_name (_("Unable to fetch AltiVec registers"));
+         }
+       #endif
+    }
+  }   
+  supply_vrregset_aix (regcache, &vmx);
+}
+
+
 /* Read from the inferior all registers if REGNO == -1 and just register
    REGNO otherwise.  */
 
@@ -312,10 +506,6 @@ void
 rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = regcache->arch ();
-  if (regno != -1)
-    fetch_register (regcache, regno);
-
-  else
     {
       ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
 
@@ -331,7 +521,18 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
       if (tdep->ppc_fp0_regnum >= 0)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
-
+      
+      if (have_ptrace_getvrregs)
+        if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) 
+        {
+           fetch_altivec_registers_aix (regcache);
+        }
+
+     if (have_ptrace_getsetvsxregs)
+         if (tdep->ppc_vsr0_upper_regnum != -1)
+          {
+            fetch_vsx_registers_aix (regcache);
+          }
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -346,6 +547,15 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+      return tdesc_powerpc_vsx64;
+   else
+      return tdesc_powerpc_vsx32;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index d47974b51d1..67ae8a6a54a 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,22 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+   
+  
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -145,7 +161,7 @@ aix_sighandle_frame_prev_register (frame_info_ptr this_frame,
 
 static int
 aix_sighandle_frame_sniffer (const struct frame_unwind *self,
-			     frame_info_ptr this_frame,
+			     frame_info_ptr this_frame, 
 			     void **this_prologue_cache)
 {
   CORE_ADDR pc = get_frame_pc (this_frame);
@@ -237,6 +253,190 @@ rs6000_aix_collect_regset (const struct regset *regset,
   ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
 }
 
+/* Return non-zero if the architecture described by GDBARCH has
+   VSX registers (vsr0 --- vsr63).  */
+static int
+rs6000_aix_vsx_support_p (struct gdbarch *gdbarch)
+{
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  return tdep->ppc_vsr0_regnum >= 0;
+}
+
+/* Return non-zero if the architecture described by GDBARCH has
+   Altivec registers (vr0 --- vr31, vrsave and vscr).  */
+static int
+rs6000_aix_altivec_support_p (struct gdbarch *gdbarch)
+{
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  return (tdep->ppc_vr0_regnum >= 0
+   && tdep->ppc_vrsave_regnum >= 0);
+}
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+                  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                  int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                     int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+
+  if (!rs6000_aix_altivec_support_p (gdbarch))
+    return;
+  
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+    && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+  
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                     int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+
+  if (!rs6000_aix_vsx_support_p (gdbarch))
+    return;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum;
+     i < tdep->ppc_vsr0_upper_regnum + 32;
+                           i++, offset++)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset * 8, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                      const struct regcache *regcache,
+                      int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+
+  if (!rs6000_aix_vsx_support_p (gdbarch))
+    return;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vsr0_upper_regnum;
+     i < tdep->ppc_vsr0_upper_regnum + 32;
+                                     i++)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+} 
+
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                      const struct regcache *regcache,
+                      int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  if (!rs6000_aix_altivec_support_p (gdbarch))
+    return;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix32_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix32_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
 /* AIX register set.  */
 
 static const struct regset rs6000_aix32_regset =
@@ -262,10 +462,19 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+   
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+ 
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx", cb_data);    
 }
 
 
@@ -351,7 +560,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
       arg = args[argno];
       type = check_typedef (value_type (arg));
-      len = type->length ();
+      len = type->length (); 
 
       if (type->code () == TYPE_CODE_FLT)
 	{
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 8b6d666bbe7..6e8ffc5fb0d 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
       /* 001110 00000 00000 iiii iiii iiii iiii  */
       /* 001110 01110 00000 iiii iiii iiii iiii  */
       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM */
-	       || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM */
+	       || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM */
+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4, SIMM */ 
 	{
 	  if ((op & 0xffff0000) == 0x38000000)
 	    r0_contains_arg = 0;
@@ -1986,24 +1987,21 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 	}
       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */      
       /* 011111 sssss 11111 00000 00111001110 */
-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
-	{
-	  if (pc == (li_found_pc + 4))
-	    {
-	      vr_reg = GET_SRC_REG (op);
-	      /* If this is the first vector reg to be saved, or if
-		 it has a lower number than others previously seen,
-		 reupdate the frame info.  */
-	      if (fdata->saved_vr == -1 || fdata->saved_vr > vr_reg)
-		{
-		  fdata->saved_vr = vr_reg;
-		  fdata->vr_offset = vr_saved_offset + offset;
-		}
-	      vr_saved_offset = -1;
-	      vr_reg = -1;
-	      li_found_pc = 0;
-	    }
-	}
+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1, r5 */
+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1, r5 */
+               || (op & 0xfc1ff000) == 0x7c012000)   
+      {
+        vr_reg = GET_SRC_REG (op);
+        /* If this is the first vector reg to be saved, or if
+       	   it has a lower number than others previously seen,
+       	   reupdate the frame info.  */
+        fdata->saved_vr = vr_reg;
+        fdata->vr_offset = vr_saved_offset;
+        vr_saved_offset = -1;
+        vr_reg = -1;
+        li_found_pc = 0;
+      }
       /* End AltiVec related instructions.  */
 
       /* Start BookE related instructions.  */
@@ -2665,8 +2663,8 @@ rs6000_convert_register_p (struct gdbarch *gdbarch, int regnum,
 	  && regnum >= tdep->ppc_fp0_regnum
 	  && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs
 	  && type->code () == TYPE_CODE_FLT
-	  && (type->length ()
-	      != builtin_type (gdbarch)->builtin_double->length ()));
+          && (type->length ()
+              != builtin_type (gdbarch)->builtin_double->length ()));
 }
 
 static int
@@ -3466,7 +3464,7 @@ struct ppc_variant
     unsigned long mach;
 
     /* Target description for this variant.  */
-    const struct target_desc **tdesc;
+    struct target_desc **tdesc;
   };
 
 static struct ppc_variant variants[] =
@@ -3474,7 +3472,7 @@ static struct ppc_variant variants[] =
   {"powerpc", "PowerPC user-level", bfd_arch_powerpc,
    bfd_mach_ppc, &tdesc_powerpc_altivec32},
   {"power", "POWER user-level", bfd_arch_rs6000,
-   bfd_mach_rs6k, &tdesc_rs6000},
+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},
   {"403", "IBM PowerPC 403", bfd_arch_powerpc,
    bfd_mach_ppc_403, &tdesc_powerpc_403},
   {"405", "IBM PowerPC 405", bfd_arch_powerpc,
@@ -3504,7 +3502,7 @@ static struct ppc_variant variants[] =
   {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc,
    bfd_mach_ppc64, &tdesc_powerpc_altivec64},
   {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
-   bfd_mach_ppc_620, &tdesc_powerpc_64},
+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},
   {"630", "Motorola PowerPC 630", bfd_arch_powerpc,
    bfd_mach_ppc_630, &tdesc_powerpc_64},
   {"a35", "PowerPC A35", bfd_arch_powerpc,
@@ -3680,18 +3678,15 @@ rs6000_frame_cache (frame_info_ptr this_frame, void **this_cache)
   /* if != -1, fdata.saved_vr is the smallest number of saved_vr.
      All vr's from saved_vr to vr31 are saved.  */
   if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
-    {
-      if (fdata.saved_vr >= 0)
-	{
-	  int i;
-	  CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
-	  for (i = fdata.saved_vr; i < 32; i++)
-	    {
-	      cache->saved_regs[tdep->ppc_vr0_regnum + i].set_addr (vr_addr);
-	      vr_addr += register_size (gdbarch, tdep->ppc_vr0_regnum);
-	    }
-	}
-    }
+  {
+    int i;
+    CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
+    for (i = 0; i < 66; i++)
+    {
+      cache->saved_regs[tdep->ppc_vsr0_upper_regnum + i].set_addr (vr_addr);
+      vr_addr += register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
+    } 
+  } 
 
   /* if != -1, fdata.saved_ev is the smallest number of saved_ev.
      All vr's from saved_ev to ev31 are saved. ?????  */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2022-10-13 10:52 [PATCH] Enable vector instruction debugging for AIX Aditya Kamath1
  2022-10-13 10:52 ` Aditya Kamath1
@ 2022-10-14 12:41 ` Ulrich Weigand
  2022-10-28 10:35   ` Aditya Kamath1
  1 sibling, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2022-10-14 12:41 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Please find attached the patch. [See 0001-PATCH-Enable-Vector-support-
for-AIX.patch]

Some comments on the patch inline.

>diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
>index 57e5756e144..15400f5b90d 100644
--- a/gdb/aix-thread.c
>+++ b/gdb/aix-thread.c
>@@ -1347,11 +1347,75 @@ fetch_regs_kernel_thread (struct regcache
*regcache, int regno,
> 	  supply_sprs32 (regcache, sprs32.pt_iar, sprs32.pt_msr,
sprs32.pt_cr,
> 			 sprs32.pt_lr, sprs32.pt_ctr, sprs32.pt_xer,
> 			 sprs32.pt_fpscr);
>-
>-	  if (tdep->ppc_mq_regnum >= 0)
>-	    regcache->raw_supply (tdep->ppc_mq_regnum, (char *)
&sprs32.pt_mq);

Why remove this support?  That looks unrelated.

>+  /* vector registers */

Coding style, should use full sentence here (and elsewhere), e.g.:
  /* Vector registers. */

>+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
>+  {
>+    int ret = 0;
>+    int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep-
>ppc_vr0_regnum + 1;
>+    __vmx_context_t vmx;
>+    memset(&vmx, 0, sizeof(__vmx_context_t));
>+    if (__power_vmx())

Are these types/functions (__vmx_context_t, __power_vmx) available
unconditionally, or does there need to be some configure check
(to avoid breaking compilation on older AIX version for example).

>+    {
>+       ret = ptrace64 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);

The rest of the code uses "ptrace64aix" to use either ptrace64
or ptracex depending on what's available.  Why is this not needed
here?

>+       if (ret < 0)
>+       {
>+         if (errno == ENXIO)
>+           return;
>+         perror_with_name (_("Unable to fetch AltiVec registers"));
>+       }

In the rest of this function, a failing ptrace call causes the
registers to be initialized to zero.  Why is it different here?

>+static void
>+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)

Please move the "fill" routines next to the other "fill" routines.
Also, add a comment before the routine like with the others.

>diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
>index cb141427696..e989a9a6739 100644
>--- a/gdb/rs6000-aix-nat.c
>+++ b/gdb/rs6000-aix-nat.c
>@@ -54,6 +54,19 @@
> #include <sys/ldr.h>
> #include <sys/systemcfg.h>
> 
>+#include "gdbthread.h"

What is this needed for here?

>+#include <sys/context.h>
>+#include <sys/pthdebug.h>

Are these available unconditionally?

>+int have_ptrace_getvrregs = 1;
>+int have_ptrace_getsetvsxregs = 1;

These aren't handled consistenly in the rest of the code.
You should decide how you plan to handle the non-availability
of these ptrace features (silently ignore, treat as zero,
treat as unavailable) and then handle them consistently.


>+static void
>+store_vsx_register_aix (struct regcache *regcache, int regno)
>+{
>+  int ret;
>+  struct gdbarch *gdbarch = regcache->arch ();
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  struct thrdentry64 thrdentry;
>+  __vsx_context_t vsx;
>+  pid_t pid = inferior_ptid.pid ();
>+  tid64_t  thrd_i = 0;
>+
>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;
>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx()) 
>+  {
>+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);

Same question as in aix-thread.c - should this check ARCH64 to
see if ptrace64 is even available?  It's strange to have those
checks everywhere else in this file but not here.

Similar question whether getthrds64 etc. are available
unconditionally.

>+    if (ret < 0)
>+    {
>+       if (errno == ENXIO)
>+       {
>+         /* have_ptrace_getsetvsxregs = 0; */
>+         warning (_("Unable to fetch VSX registers."));
>+         return;
>+       }

See above.  Final patches submitted upstream should never have
any code commented out - please resolve these questions before.

>@@ -264,6 +355,17 @@ store_register (struct regcache *regcache, int
regno)
> 
>   nr = regmap (gdbarch, regno, &isfloat);
> 
>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }

If you do it this way, it should be *before* the regmap call
(which doesn't handle any of these registers.)

>@@ -312,10 +506,6 @@ void
> rs6000_nat_target::fetch_registers (struct regcache *regcache, int
regno)
> {
>   struct gdbarch *gdbarch = regcache->arch ();
>-  if (regno != -1)
>-    fetch_register (regcache, regno);
>-
>-  else

This doesn't look right?

>+      if (have_ptrace_getvrregs)
>+        if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum !=
-1) 
>+        {
>+           fetch_altivec_registers_aix (regcache);
>+        }
>+
>+     if (have_ptrace_getsetvsxregs)
>+         if (tdep->ppc_vsr0_upper_regnum != -1)
>+          {
>+            fetch_vsx_registers_aix (regcache);
>+          }

No need for { } when it's a single statement.

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+      return tdesc_powerpc_vsx64;
>+   else
>+      return tdesc_powerpc_vsx32;
>+}

Well, is this true?  Shouldn't this check whether the machine
actually *has* VSX, and return a different tdesc otherwise?

>@@ -145,7 +161,7 @@ aix_sighandle_frame_prev_register (frame_info_ptr
this_frame,
> 
> static int
> aix_sighandle_frame_sniffer (const struct frame_unwind *self,
>-			     frame_info_ptr this_frame,
>+			     frame_info_ptr this_frame, 
> 			     void **this_prologue_cache)
> {
>   CORE_ADDR pc = get_frame_pc (this_frame);

Whitespace only change - please remove.

>+/* Return non-zero if the architecture described by GDBARCH has
>+   VSX registers (vsr0 --- vsr63).  */
>+static int
>+rs6000_aix_vsx_support_p (struct gdbarch *gdbarch)
>+{
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  return tdep->ppc_vsr0_regnum >= 0;
>+}
>+
>+/* Return non-zero if the architecture described by GDBARCH has
>+   Altivec registers (vr0 --- vr31, vrsave and vscr).  */
>+static int
>+rs6000_aix_altivec_support_p (struct gdbarch *gdbarch)
>+{
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  return (tdep->ppc_vr0_regnum >= 0
>+   && tdep->ppc_vrsave_regnum >= 0);
>+}

Are these helpers really needed?  In other places the same check
is just performed inline.  This should be consistent everywhere.

>+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
>+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
>+                                              i++, offset += 16)

Formatting.

>+    for (i = tdep->ppc_vsr0_upper_regnum;
>+     i < tdep->ppc_vsr0_upper_regnum + 32;
>+                           i++, offset++)
>+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset
* 8, 8);

Formatting.  Also you should be consistent with code above and use
offset += 8 instead of the multiplication.

>+    for (i = tdep->ppc_vsr0_upper_regnum;
>+     i < tdep->ppc_vsr0_upper_regnum + 32;
>+                                     i++)
>+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8);

This looks wrong - it always uses offset zero?

>@@ -262,10 +462,19 @@ rs6000_aix_iterate_over_regset_sections (struct
gdbarch *gdbarch,
> 					 const struct regcache
*regcache)
> {
>   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  int have_altivec = tdep->ppc_vr0_regnum != -1;
>+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
>+   
>   if (tdep->wordsize == 4)
>     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
>   else
>     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
>+ 
>+  if (have_altivec)
>+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec",
cb_data);
>+
>+  if (have_vsx)
>+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx",
cb_data);    

As those regsets are the same between 32- and 64-bit, they should
probably be just called rs6000_aix_vrregset etc.

>@@ -351,7 +560,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch,
struct value *function,
> 
>       arg = args[argno];
>       type = check_typedef (value_type (arg));
>-      len = type->length ();
>+      len = type->length (); 

Another whitespace-only change, please remove.
 
>index 8b6d666bbe7..6e8ffc5fb0d 100644
>--- a/gdb/rs6000-tdep.c
>+++ b/gdb/rs6000-tdep.c
>@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch,
CORE_ADDR pc, CORE_ADDR lim_pc,
>       /* 001110 00000 00000 iiii iiii iiii iiii  */
>       /* 001110 01110 00000 iiii iiii iiii iiii  */
>       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM
*/
>-	       || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM
*/
>+	       || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM
*/
>+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4,
SIMM */ 
> 	{
> 	  if ((op & 0xffff0000) == 0x38000000)
> 	    r0_contains_arg = 0;
>@@ -1986,24 +1987,21 @@ skip_prologue (struct gdbarch *gdbarch,
CORE_ADDR pc, CORE_ADDR lim_pc,
> 	}
>       /* Store vector register S at (r31+r0) aligned to 16
bytes.  */      
>       /* 011111 sssss 11111 00000 00111001110 */
>-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0
*/
>-	{
>-	  if (pc == (li_found_pc + 4))
>-	    {
>-	      vr_reg = GET_SRC_REG (op);
>-	      /* If this is the first vector reg to be saved, or if
>-		 it has a lower number than others previously seen,
>-		 reupdate the frame info.  */
>-	      if (fdata->saved_vr == -1 || fdata->saved_vr > vr_reg)
>-		{
>-		  fdata->saved_vr = vr_reg;
>-		  fdata->vr_offset = vr_saved_offset + offset;
>-		}
>-	      vr_saved_offset = -1;
>-	      vr_reg = -1;
>-	      li_found_pc = 0;
>-	    }
>-	}
>+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0
*/
>+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1,
r5 */
>+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1,
r5 */
>+               || (op & 0xfc1ff000) == 0x7c012000)   
>+      {
>+        vr_reg = GET_SRC_REG (op);
>+        /* If this is the first vector reg to be saved, or if
>+       	   it has a lower number than others previously seen,
>+       	   reupdate the frame info.  */
>+        fdata->saved_vr = vr_reg;
>+        fdata->vr_offset = vr_saved_offset;
>+        vr_saved_offset = -1;
>+        vr_reg = -1;
>+        li_found_pc = 0;
>+      }

So I don't know enough about the details of the prologue generated
by the various compilers to understand exactly what's going on here,
but this change looks wrong - it now completely ignores the
"li_found_pc", so why even compute it?  More specifically, the
intention of the previous code was to only look for the first
instances of stvx* in the prolog at a particular place (because
later instances might serve a different purpose).  This change
just ignores all this.

Is prologue parsing even still necessary on AIX?  On Linux
these days we should always get this info via DWARF CIF.

>@@ -2665,8 +2663,8 @@ rs6000_convert_register_p (struct gdbarch
*gdbarch, int regnum,
> 	  && regnum >= tdep->ppc_fp0_regnum
> 	  && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs
> 	  && type->code () == TYPE_CODE_FLT
>-	  && (type->length ()
>-	      != builtin_type (gdbarch)->builtin_double->length ()));
>+          && (type->length ()
>+              != builtin_type (gdbarch)->builtin_double->length ()));

Another white-space only change.

>@@ -3466,7 +3464,7 @@ struct ppc_variant
>     unsigned long mach;
> 
>     /* Target description for this variant.  */
>-    const struct target_desc **tdesc;
>+    struct target_desc **tdesc;

This looks just wrong.

>@@ -3504,7 +3502,7 @@ static struct ppc_variant variants[] =
>   {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc,
>    bfd_mach_ppc64, &tdesc_powerpc_altivec64},
>   {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
>-   bfd_mach_ppc_620, &tdesc_powerpc_64},
>+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},

Should we change the default for "Motorola PowerPC 620" 
at this stage?  Can we even test on that machine?

>@@ -3680,18 +3678,15 @@ rs6000_frame_cache (frame_info_ptr this_frame,
void **this_cache)
>   /* if != -1, fdata.saved_vr is the smallest number of saved_vr.
>      All vr's from saved_vr to vr31 are saved.  */
>   if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
>-    {
>-      if (fdata.saved_vr >= 0)
>-	{
>-	  int i;
>-	  CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
>-	  for (i = fdata.saved_vr; i < 32; i++)
>-	    {
>-	      cache->saved_regs[tdep->ppc_vr0_regnum + i].set_addr
(vr_addr);
>-	      vr_addr += register_size (gdbarch, tdep->ppc_vr0_regnum);
>-	    }
>-	}
>-    }
>+  {
>+    int i;
>+    CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
>+    for (i = 0; i < 66; i++)
>+    {
>+      cache->saved_regs[tdep->ppc_vsr0_upper_regnum + i].set_addr
(vr_addr);
>+      vr_addr += register_size (gdbarch, tdep-
>ppc_vsr0_upper_regnum);
>+    } 
>+  } 

This looks wrong:
- It completely removes loading stored values for altivec registers
- It always loads VSX registers even if they haven't been saved
- It uses up to 66 "VSX upper-half" registers even though only
  32 of those exist.
- Are there even any call-saved VSX registers in the AIX ABI?
  In the
Linux ABI there aren't.

Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2022-10-14 12:41 ` Ulrich Weigand
@ 2022-10-28 10:35   ` Aditya Kamath1
  2022-10-28 12:39     ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2022-10-28 10:35 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 22323 bytes --]

Hi all,

Thank you for the feedback. Please find attached the new patch. [See: 0001-Enable-Vector-instruction-debugging-support-for-AIX.patch ]

Kindly let me know if any changes required.

I have answered point by point for the feedback below. Please find below.

Have a nice day ahead.

Thanks and regards,
Aditya.

---------------------------------------------------------------------------------------------------------------
>-
>-        if (tdep->ppc_mq_regnum >= 0)
>-          regcache->raw_supply (tdep->ppc_mq_regnum, (char *)
&sprs32.pt_mq);

Why remove this support?  That looks unrelated.

Ans = Agreed. I made a mistake. I have corrected the same.

Coding style, should use full sentence here (and elsewhere), e.g.:
  /* Vector registers. */

Ans = Taken care in all comments.


Are these types/functions (__vmx_context_t, __power_vmx) available
unconditionally, or does there need to be some configure check
(to avoid breaking compilation on older AIX version for example).

Ans = They are all available since AIX version 5.3. So it should not break.


The rest of the code uses "ptrace64aix" to use either ptrace64
or ptracex depending on what's available.  Why is this not needed
here?

Ans = Taken care in complete aix-thread.c file changes

In the rest of this function, a failing ptrace call causes the
registers to be initialized to zero.  Why is it different here?

Ans = You were right I have taken care of it. See memset () function.

Please move the "fill" routines next to the other "fill" routines.
Also, add a comment before the routine like with the others.

Ans = I have done it.

>+#include "gdbthread.h"

What is this needed for here?

Ans = I have removed it.

>+#include <sys/context.h>
>+#include <sys/pthdebug.h>

Are these available unconditionally?

 ANS = Available from AIX 5.3

>+int have_ptrace_getvrregs = 1;
>+int have_ptrace_getsetvsxregs = 1;

These aren't handled consistenly in the rest of the code.
You should decide how you plan to handle the non-availability
of these ptrace features (silently ignore, treat as zero,
treat as unavailable) and then handle them consistently.

ANS = Taken care and eliminated. Thank you for the suggestion.

+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);

Same question as in aix-thread.c - should this check ARCH64 to
see if ptrace64 is even available?

ANS = Taken care here as well

See above.  Final patches submitted upstream should never have
any code commented out - please resolve these questions before.

ANS = removed. Thanks

>   nr = regmap (gdbarch, regno, &isfloat);
>
>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }

If you do it this way, it should be *before* the regmap call
(which doesn't handle any of these registers.)

ANS = Implemented. Thanks


>-  if (regno != -1)
>-    fetch_register (regcache, regno);
>-
>-  else

This doesn't look right?

ANS = Yes, I understood that sometimes when we know what register to write we need it. I have made some changed here in the patch.

+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+      return tdesc_powerpc_vsx64;
>+   else
>+      return tdesc_powerpc_vsx32;
>+}

Well, is this true?  Shouldn't this check whether the machine
actually *has* VSX, and return a different tdesc otherwise?

ANS = AIX 5.3 onwards we get those _vmx_context_t, __power_vmx variables to support these target descriptions.

 Whitespace only change - please remove.

ANS = Done

Are these helpers really needed?  In other places the same check
is just performed inline.  This should be consistent everywhere.


ANS = Done


for (i = tdep->ppc_vsr0_upper_regnum;
>+     i < tdep->ppc_vsr0_upper_regnum + 32;
>+                           i++, offset++)
>+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset
* 8, 8);
Formatting.

ANS = I have taken care. But in case there is an update for large for loop statements let me know.


>+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset
* 8, 8);

Formatting.  Also you should be consistent with code above and use
offset += 8 instead of the multiplication.

ANS = Done

>+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8);

This looks wrong - it always uses offset zero?

ANS = Corrected


>+  if (have_altivec)
>+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec",
cb_data);
>+
>+  if (have_vsx)
>+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx",
cb_data);
As those regsets are the same between 32- and 64-bit, they should
probably be just called rs6000_aix_vrregset etc.

ANS = No, their offsets are different. Hence, we have different variables for them.


>-      {
>-        if (pc == (li_found_pc + 4))
>-          {
>-            vr_reg = GET_SRC_REG (op);
>-            /* If this is the first vector reg to be saved, or if
>-               it has a lower number than others previously seen,
>-               reupdate the frame info.  */
>-            if (fdata->saved_vr == -1 || fdata->saved_vr > vr_reg)
>-              {
>-                fdata->saved_vr = vr_reg;
>-                fdata->vr_offset = vr_saved_offset + offset;
>-              }
>-            vr_saved_offset = -1;
>-            vr_reg = -1;
>-            li_found_pc = 0;
>-          }
So I don't know enough about the details of the prologue generated
by the various compilers to understand exactly what's going on here,
but this change looks wrong - it now completely ignores the
"li_found_pc", so why even compute it?  More specifically, the
intention of the previous code was to only look for the first
instances of stvx* in the prolog at a particular place (because
later instances might serve a different purpose).  This change
just ignores all this.

ANS = I agree, I got this wrong in the previous patch. I have corrected it now. Kindly let me know.

>-   bfd_mach_ppc_620, &tdesc_powerpc_64},
>+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},

Should we change the default for "Motorola PowerPC 620"
at this stage?  Can we even test on that machine?
ANS = No. No we cannot test on that machine.



>   /* if != -1, fdata.saved_vr is the smallest number of saved_vr.
>      All vr's from saved_vr to vr31 are saved.  */
>   if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
>-    {
>-      if (fdata.saved_vr >= 0)
>-      {
>-        int i;
>-        CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
>-        for (i = fdata.saved_vr; i < 32; i++)
>-          {
>-            cache->saved_regs[tdep->ppc_vr0_regnum + i].set_addr
(vr_addr);
>-            vr_addr += register_size (gdbarch, tdep->ppc_vr0_regnum);
>-          }
>-      }
>-    }
>+  {
>+    int i;
>+    CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
>+    for (i = 0; i < 66; i++)
>+    {
>+      cache->saved_regs[tdep->ppc_vsr0_upper_regnum + i].set_addr
(vr_addr);
>+      vr_addr += register_size (gdbarch, tdep-
>ppc_vsr0_upper_regnum);
>+    }
>+  }

This looks wrong:
- It completely removes loading stored values for altivec registers
- It always loads VSX registers even if they haven't been saved
- It uses up to 66 "VSX upper-half" registers even though only

ANS =  I got this wrong in the previous patch. I have corrected it now. Kindly let me know.




________________________________
From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Sent: 14 October 2022 18:11
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>; Aditya Kamath1 <Aditya.Kamath1@ibm.com>; simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Please find attached the patch. [See 0001-PATCH-Enable-Vector-support-
for-AIX.patch]

Some comments on the patch inline.

>diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
>index 57e5756e144..15400f5b90d 100644
--- a/gdb/aix-thread.c
>+++ b/gdb/aix-thread.c
>@@ -1347,11 +1347,75 @@ fetch_regs_kernel_thread (struct regcache
*regcache, int regno,
>          supply_sprs32 (regcache, sprs32.pt_iar, sprs32.pt_msr,
sprs32.pt_cr,
>                         sprs32.pt_lr, sprs32.pt_ctr, sprs32.pt_xer,
>                         sprs32.pt_fpscr);
>-
>-        if (tdep->ppc_mq_regnum >= 0)
>-          regcache->raw_supply (tdep->ppc_mq_regnum, (char *)
&sprs32.pt_mq);

Why remove this support?  That looks unrelated.

>+  /* vector registers */

Coding style, should use full sentence here (and elsewhere), e.g.:
  /* Vector registers. */

>+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
>+  {
>+    int ret = 0;
>+    int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep-
>ppc_vr0_regnum + 1;
>+    __vmx_context_t vmx;
>+    memset(&vmx, 0, sizeof(__vmx_context_t));
>+    if (__power_vmx())

Are these types/functions (__vmx_context_t, __power_vmx) available
unconditionally, or does there need to be some configure check
(to avoid breaking compilation on older AIX version for example).

>+    {
>+       ret = ptrace64 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);

The rest of the code uses "ptrace64aix" to use either ptrace64
or ptracex depending on what's available.  Why is this not needed
here?

>+       if (ret < 0)
>+       {
>+         if (errno == ENXIO)
>+           return;
>+         perror_with_name (_("Unable to fetch AltiVec registers"));
>+       }

In the rest of this function, a failing ptrace call causes the
registers to be initialized to zero.  Why is it different here?

>+static void
>+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)

Please move the "fill" routines next to the other "fill" routines.
Also, add a comment before the routine like with the others.

>diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
>index cb141427696..e989a9a6739 100644
>--- a/gdb/rs6000-aix-nat.c
>+++ b/gdb/rs6000-aix-nat.c
>@@ -54,6 +54,19 @@
> #include <sys/ldr.h>
> #include <sys/systemcfg.h>
>
>+#include "gdbthread.h"

What is this needed for here?

>+#include <sys/context.h>
>+#include <sys/pthdebug.h>

Are these available unconditionally?

>+int have_ptrace_getvrregs = 1;
>+int have_ptrace_getsetvsxregs = 1;

These aren't handled consistenly in the rest of the code.
You should decide how you plan to handle the non-availability
of these ptrace features (silently ignore, treat as zero,
treat as unavailable) and then handle them consistently.


>+static void
>+store_vsx_register_aix (struct regcache *regcache, int regno)
>+{
>+  int ret;
>+  struct gdbarch *gdbarch = regcache->arch ();
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  struct thrdentry64 thrdentry;
>+  __vsx_context_t vsx;
>+  pid_t pid = inferior_ptid.pid ();
>+  tid64_t  thrd_i = 0;
>+
>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;
>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx())
>+  {
>+    ret = ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);

Same question as in aix-thread.c - should this check ARCH64 to
see if ptrace64 is even available?  It's strange to have those
checks everywhere else in this file but not here.

Similar question whether getthrds64 etc. are available
unconditionally.

>+    if (ret < 0)
>+    {
>+       if (errno == ENXIO)
>+       {
>+         /* have_ptrace_getsetvsxregs = 0; */
>+         warning (_("Unable to fetch VSX registers."));
>+         return;
>+       }

See above.  Final patches submitted upstream should never have
any code commented out - please resolve these questions before.

>@@ -264,6 +355,17 @@ store_register (struct regcache *regcache, int
regno)
>
>   nr = regmap (gdbarch, regno, &isfloat);
>
>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }

If you do it this way, it should be *before* the regmap call
(which doesn't handle any of these registers.)

>@@ -312,10 +506,6 @@ void
> rs6000_nat_target::fetch_registers (struct regcache *regcache, int
regno)
> {
>   struct gdbarch *gdbarch = regcache->arch ();
>-  if (regno != -1)
>-    fetch_register (regcache, regno);
>-
>-  else

This doesn't look right?

>+      if (have_ptrace_getvrregs)
>+        if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum !=
-1)
>+        {
>+           fetch_altivec_registers_aix (regcache);
>+        }
>+
>+     if (have_ptrace_getsetvsxregs)
>+         if (tdep->ppc_vsr0_upper_regnum != -1)
>+          {
>+            fetch_vsx_registers_aix (regcache);
>+          }

No need for { } when it's a single statement.

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+      return tdesc_powerpc_vsx64;
>+   else
>+      return tdesc_powerpc_vsx32;
>+}

Well, is this true?  Shouldn't this check whether the machine
actually *has* VSX, and return a different tdesc otherwise?

>@@ -145,7 +161,7 @@ aix_sighandle_frame_prev_register (frame_info_ptr
this_frame,
>
> static int
> aix_sighandle_frame_sniffer (const struct frame_unwind *self,
>-                           frame_info_ptr this_frame,
>+                           frame_info_ptr this_frame,
>                             void **this_prologue_cache)
> {
>   CORE_ADDR pc = get_frame_pc (this_frame);

Whitespace only change - please remove.

>+/* Return non-zero if the architecture described by GDBARCH has
>+   VSX registers (vsr0 --- vsr63).  */
>+static int
>+rs6000_aix_vsx_support_p (struct gdbarch *gdbarch)
>+{
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  return tdep->ppc_vsr0_regnum >= 0;
>+}
>+
>+/* Return non-zero if the architecture described by GDBARCH has
>+   Altivec registers (vr0 --- vr31, vrsave and vscr).  */
>+static int
>+rs6000_aix_altivec_support_p (struct gdbarch *gdbarch)
>+{
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  return (tdep->ppc_vr0_regnum >= 0
>+   && tdep->ppc_vrsave_regnum >= 0);
>+}

Are these helpers really needed?  In other places the same check
is just performed inline.  This should be consistent everywhere.

>+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
>+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
>+                                              i++, offset += 16)

Formatting.

>+    for (i = tdep->ppc_vsr0_upper_regnum;
>+     i < tdep->ppc_vsr0_upper_regnum + 32;
>+                           i++, offset++)
>+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset
* 8, 8);

Formatting.  Also you should be consistent with code above and use
offset += 8 instead of the multiplication.

>+    for (i = tdep->ppc_vsr0_upper_regnum;
>+     i < tdep->ppc_vsr0_upper_regnum + 32;
>+                                     i++)
>+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, 0, 8);

This looks wrong - it always uses offset zero?

>@@ -262,10 +462,19 @@ rs6000_aix_iterate_over_regset_sections (struct
gdbarch *gdbarch,
>                                         const struct regcache
*regcache)
> {
>   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  int have_altivec = tdep->ppc_vr0_regnum != -1;
>+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
>+
>   if (tdep->wordsize == 4)
>     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
>   else
>     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
>+
>+  if (have_altivec)
>+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec",
cb_data);
>+
>+  if (have_vsx)
>+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx",
cb_data);

As those regsets are the same between 32- and 64-bit, they should
probably be just called rs6000_aix_vrregset etc.

>@@ -351,7 +560,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch,
struct value *function,
>
>       arg = args[argno];
>       type = check_typedef (value_type (arg));
>-      len = type->length ();
>+      len = type->length ();

Another whitespace-only change, please remove.

>index 8b6d666bbe7..6e8ffc5fb0d 100644
>--- a/gdb/rs6000-tdep.c
>+++ b/gdb/rs6000-tdep.c
>@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch,
CORE_ADDR pc, CORE_ADDR lim_pc,
>       /* 001110 00000 00000 iiii iiii iiii iiii  */
>       /* 001110 01110 00000 iiii iiii iiii iiii  */
>       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM
*/
>-             || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM
*/
>+             || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM
*/
>+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4,
SIMM */
>        {
>          if ((op & 0xffff0000) == 0x38000000)
>            r0_contains_arg = 0;
>@@ -1986,24 +1987,21 @@ skip_prologue (struct gdbarch *gdbarch,
CORE_ADDR pc, CORE_ADDR lim_pc,
>        }
>       /* Store vector register S at (r31+r0) aligned to 16
bytes.  */
>       /* 011111 sssss 11111 00000 00111001110 */
>-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0
*/
>-      {
>-        if (pc == (li_found_pc + 4))
>-          {
>-            vr_reg = GET_SRC_REG (op);
>-            /* If this is the first vector reg to be saved, or if
>-               it has a lower number than others previously seen,
>-               reupdate the frame info.  */
>-            if (fdata->saved_vr == -1 || fdata->saved_vr > vr_reg)
>-              {
>-                fdata->saved_vr = vr_reg;
>-                fdata->vr_offset = vr_saved_offset + offset;
>-              }
>-            vr_saved_offset = -1;
>-            vr_reg = -1;
>-            li_found_pc = 0;
>-          }
>-      }
>+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0
*/
>+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1,
r5 */
>+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1,
r5 */
>+               || (op & 0xfc1ff000) == 0x7c012000)
>+      {
>+        vr_reg = GET_SRC_REG (op);
>+        /* If this is the first vector reg to be saved, or if
>+                  it has a lower number than others previously seen,
>+                  reupdate the frame info.  */
>+        fdata->saved_vr = vr_reg;
>+        fdata->vr_offset = vr_saved_offset;
>+        vr_saved_offset = -1;
>+        vr_reg = -1;
>+        li_found_pc = 0;
>+      }

So I don't know enough about the details of the prologue generated
by the various compilers to understand exactly what's going on here,
but this change looks wrong - it now completely ignores the
"li_found_pc", so why even compute it?  More specifically, the
intention of the previous code was to only look for the first
instances of stvx* in the prolog at a particular place (because
later instances might serve a different purpose).  This change
just ignores all this.

Is prologue parsing even still necessary on AIX?  On Linux
these days we should always get this info via DWARF CIF.

>@@ -2665,8 +2663,8 @@ rs6000_convert_register_p (struct gdbarch
*gdbarch, int regnum,
>          && regnum >= tdep->ppc_fp0_regnum
>          && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs
>          && type->code () == TYPE_CODE_FLT
>-        && (type->length ()
>-            != builtin_type (gdbarch)->builtin_double->length ()));
>+          && (type->length ()
>+              != builtin_type (gdbarch)->builtin_double->length ()));

Another white-space only change.

>@@ -3466,7 +3464,7 @@ struct ppc_variant
>     unsigned long mach;
>
>     /* Target description for this variant.  */
>-    const struct target_desc **tdesc;
>+    struct target_desc **tdesc;

This looks just wrong.

>@@ -3504,7 +3502,7 @@ static struct ppc_variant variants[] =
>   {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc,
>    bfd_mach_ppc64, &tdesc_powerpc_altivec64},
>   {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
>-   bfd_mach_ppc_620, &tdesc_powerpc_64},
>+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},

Should we change the default for "Motorola PowerPC 620"
at this stage?  Can we even test on that machine?

>@@ -3680,18 +3678,15 @@ rs6000_frame_cache (frame_info_ptr this_frame,
void **this_cache)
>   /* if != -1, fdata.saved_vr is the smallest number of saved_vr.
>      All vr's from saved_vr to vr31 are saved.  */
>   if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
>-    {
>-      if (fdata.saved_vr >= 0)
>-      {
>-        int i;
>-        CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
>-        for (i = fdata.saved_vr; i < 32; i++)
>-          {
>-            cache->saved_regs[tdep->ppc_vr0_regnum + i].set_addr
(vr_addr);
>-            vr_addr += register_size (gdbarch, tdep->ppc_vr0_regnum);
>-          }
>-      }
>-    }
>+  {
>+    int i;
>+    CORE_ADDR vr_addr = cache->base + fdata.vr_offset;
>+    for (i = 0; i < 66; i++)
>+    {
>+      cache->saved_regs[tdep->ppc_vsr0_upper_regnum + i].set_addr
(vr_addr);
>+      vr_addr += register_size (gdbarch, tdep-
>ppc_vsr0_upper_regnum);
>+    }
>+  }

This looks wrong:
- It completely removes loading stored values for altivec registers
- It always loads VSX registers even if they haven't been saved
- It uses up to 66 "VSX upper-half" registers even though only
  32 of those exist.
- Are there even any call-saved VSX registers in the AIX ABI?
  In the
Linux ABI there aren't.

Bye,
Ulrich


[-- Attachment #2: 0001-Enable-Vector-instruction-debugging-support-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 22827 bytes --]

From 43b8eebc56715fde2dc701e52789e1845c0c95f9 Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Fri, 28 Oct 2022 04:59:06 -0500
Subject: [PATCH] Enable Vector instruction debugging support for AIX

---
 gdb/aix-thread.c      | 125 +++++++++++++++++++++++++
 gdb/rs6000-aix-nat.c  | 210 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-tdep.c | 179 +++++++++++++++++++++++++++++++++++
 gdb/rs6000-tdep.c     |  12 ++-
 4 files changed, 520 insertions(+), 6 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index e556c153576..6bcb9af7771 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -1352,6 +1352,43 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	    regcache->raw_supply (tdep->ppc_mq_regnum, (char *) &sprs32.pt_mq);
 	}
     }
+   
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
+    {
+      int ret = 0;
+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+          memset(&vmx, 0, sizeof(__vmx_context_t));
+        for (i = 0; i < num_of_vrregs; i++)
+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      }
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1 && regno >= tdep->ppc_vsr0_upper_regnum)
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        int ret = 0;
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          memset(&vsx, 0, sizeof(__vsx_context_t));
+        for (i = 0; i < ppc_num_vshrs; i++)
+          regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+        }
+    }
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from the
@@ -1496,6 +1533,37 @@ fill_sprs32 (const struct regcache *regcache,
     regcache->raw_collect (tdep->ppc_fpscr_regnum, fpscr);
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  int regno;
+
+  for (regno = 0; regno < num_of_vrregs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+                                 &(vmx->__vr[0]) + regno);
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store all registers into pthread PDTID, which doesn't have a kernel
    thread.
 
@@ -1602,6 +1670,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   double fprs[ppc_num_fprs];
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
+  int ret = 0; 
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1692,6 +1761,62 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)
+    {
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch AltiVec registers."));
+            memset(&vmx, 0, sizeof(__vmx_context_t)); 
+          }
+          fill_altivec(regcache, &vmx);
+          if (arch64)
+            ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+          else
+            ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+          if (ret < 0)
+            perror_with_name (_("Unable to store AltiVec register."));
+        }
+      }
+    }
+ 
+    /* vmx registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1 && regno >= tdep->ppc_vsr0_upper_regnum)
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        if (arch64)
+          ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch VSX registers."));
+            memset(&vsx, 0, sizeof(__vsx_context_t)); 
+          }
+        }
+        fill_vsx (regcache, &vsx);
+        if (arch64)
+          ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          perror_with_name (_("Unable to store VSX register."));
+      }
+   } 
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index cb141427696..3a5f23b4ba7 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -54,6 +54,14 @@
 #include <sys/ldr.h>
 #include <sys/systemcfg.h>
 
+#include <sys/context.h>
+#include <sys/pthdebug.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -91,6 +99,8 @@ class rs6000_nat_target final : public inf_ptrace_target
 
   ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override
@@ -187,6 +197,174 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         warning (_("Unable to fetch VSX registers."));
+         return;
+       }
+    }
+  }
+  regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                       regno - tdep->ppc_vsr0_upper_regnum);
+
+  if (ARCH64 ())
+    ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+  else
+    ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store VSX register."));
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         warning (_("Unable to fetch AltiVec registers."));
+         return;
+       }
+    }
+  }
+
+  regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                - tdep->ppc_vr0_regnum);
+
+  if (ARCH64 ())
+    ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+  else
+    ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+  if (ret < 0)
+     perror_with_name (_("Unable to store AltiVec register."));
+
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    supply_vrregset_aix (regcache, &vmx);      
+  }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+    supply_vsxregset_aix (regcache, &vsx);
+  }
+}
+
 /* Fetch register REGNO from the inferior.  */
 
 static void
@@ -233,7 +411,7 @@ fetch_register (struct regcache *regcache, int regno)
 	    *addr = buf;
 	}
     }
-
+  
   if (!errno)
     regcache->raw_supply (regno, (char *) addr);
   else
@@ -244,6 +422,9 @@ fetch_register (struct regcache *regcache, int regno)
 #endif
       errno = 0;
     }
+
+  fetch_altivec_registers_aix (regcache);
+  fetch_vsx_registers_aix (regcache);
 }
 
 /* Store register REGNO back into the inferior.  */
@@ -262,6 +443,17 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -314,7 +506,6 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
   struct gdbarch *gdbarch = regcache->arch ();
   if (regno != -1)
     fetch_register (regcache, regno);
-
   else
     {
       ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
@@ -331,7 +522,13 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
       if (tdep->ppc_fp0_regnum >= 0)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
+      
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) 
+        fetch_altivec_registers_aix (regcache);
 
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+          
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -346,6 +543,15 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+      return tdesc_powerpc_vsx64;
+   else
+      return tdesc_powerpc_vsx32;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index d47974b51d1..dc3508e503d 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,176 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+                                                   + 32; i++, offset += 8)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i;
+    int offset = 0;
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+                                                  + 32; i++, offset += 8)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+              tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix32_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix32_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +432,19 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx", cb_data); 
 }
 
 
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 8b6d666bbe7..9588068bfa9 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
       /* 001110 00000 00000 iiii iiii iiii iiii  */
       /* 001110 01110 00000 iiii iiii iiii iiii  */
       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM */
-	       || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM */
+	       || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM */
+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4, SIMM */ 
 	{
 	  if ((op & 0xffff0000) == 0x38000000)
 	    r0_contains_arg = 0;
@@ -1986,7 +1987,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 	}
       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */      
       /* 011111 sssss 11111 00000 00111001110 */
-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1, r5 */
+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1, r5 */
+               || (op & 0xfc1ff000) == 0x7c012000)   
 	{
 	  if (pc == (li_found_pc + 4))
 	    {
@@ -3474,7 +3478,7 @@ static struct ppc_variant variants[] =
   {"powerpc", "PowerPC user-level", bfd_arch_powerpc,
    bfd_mach_ppc, &tdesc_powerpc_altivec32},
   {"power", "POWER user-level", bfd_arch_rs6000,
-   bfd_mach_rs6k, &tdesc_rs6000},
+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},
   {"403", "IBM PowerPC 403", bfd_arch_powerpc,
    bfd_mach_ppc_403, &tdesc_powerpc_403},
   {"405", "IBM PowerPC 405", bfd_arch_powerpc,
@@ -3504,7 +3508,7 @@ static struct ppc_variant variants[] =
   {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc,
    bfd_mach_ppc64, &tdesc_powerpc_altivec64},
   {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
-   bfd_mach_ppc_620, &tdesc_powerpc_64},
+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},
   {"630", "Motorola PowerPC 630", bfd_arch_powerpc,
    bfd_mach_ppc_630, &tdesc_powerpc_64},
   {"a35", "PowerPC A35", bfd_arch_powerpc,
-- 
2.31.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2022-10-28 10:35   ` Aditya Kamath1
@ 2022-10-28 12:39     ` Ulrich Weigand
  2022-11-14 16:26       ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2022-10-28 12:39 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Thank you for the feedback. Please find attached the new patch.

Thanks for the update!  Please find additional comments below.

>Kindly let me know if any changes required. 

>@@ -1352,6 +1352,43 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,

I just noticed that there seem to be two methods, handling
user threads and kernel threads, respectively.  You patch
only adds support for VMX/VSX registers to kernel threads
-- should this also be done for user threads?  (Same applies
to store_regs_... of course.)

>+  /* vector registers.  */
>+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)

This check isn't quite correct.  I think it should be:
  if the target has vector registers
  and (all registers are requested, i.e. regno == -1
       or a vector register is requested, i.e. regno is a VR)

Something along these lines:
 if (tdep->ppc_vr0_regnum != -1 && tdep->vrsave_regnum != -1
     && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
                         && regno <= tdep->ppc_vrsave_regnum))

(Similar for VSX.  Also applies to the store_regs_... code.)

>+      if (__power_vmx())
>+      {
>+        if (arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        if (ret < 0)
>+          memset(&vmx, 0, sizeof(__vmx_context_t));
>+        for (i = 0; i < num_of_vrregs; i++)
>+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
>+      }

So if access to VMX registers fails because ptrace fails,
you now zero out the registers.  But if access fails because
__power_vmx() fails, the registers are left undefined.

Is this intentional?  What the meaning of this difference?

>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
>+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
>+                                 &(vmx->__vr[0]) + regno);

Is there a reason for not using &(vmx->__vr[regno]) like above?
That would seem to be more straightforward.

>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;
>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx())
>+  {
>+    if (ARCH64 ())
>+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
>+    else
>+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);

Just noticed this here.  Everywhere else in this file, a *pid* is
passed to rs6000_ptrace64/32.  Only in this new routine, you're
apparently passing a thread ID.   Why should this be different just
for these registers?  Shouldn't per-thread registers be handled in
aix-thread.c anyway?

>@@ -233,7 +411,7 @@ fetch_register (struct regcache *regcache, int regno)
>            *addr = buf;
>        }
>     }
>-
>+  
>   if (!errno)
>     regcache->raw_supply (regno, (char *) addr);
>   else

Please remove these no-op changes from the patch.

>@@ -244,6 +422,9 @@ fetch_register (struct regcache *regcache, int regno)
> #endif
>       errno = 0;
>     }
>+
>+  fetch_altivec_registers_aix (regcache);
>+  fetch_vsx_registers_aix (regcache);
> }


I think you should call this only if the requested regno
actually *is* a VMX or VSX register.  Also, if this is the
case, you don't need to do anything else in this routine.
This should be separate checks at the beginning of the
routine, just like you now do in store_register.

>@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
>       /* 001110 00000 00000 iiii iiii iiii iiii  */
>       /* 001110 01110 00000 iiii iiii iiii iiii  */
>       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM */
>-              || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM */
>+              || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM */
>+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4, SIMM */ 

Please fix the tabs vs. spaces, and keep the comments at the end aligned.

More importantly, the code doesn't match the comment before the if
any more.  This now accepts many other "li" variants, and even a few
"addi" that aren't actually "li" (it only verifies four out of the
five bits of "RA" - for "li" they must all be zero).

Can you explain what exact set of instructions this is *intended*
to match now, and why?  Then we can figure out what the appropriate
bitmask to implement the check would be.

These checks are difficult enough to understand anyway, so it is
crucially important that the comments explaining them are correct
and match what is being done.  So any change must be accompanied
by a corresponding comment update.


>@@ -1986,7 +1987,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
>        }
>       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */
>       /* 011111 sssss 11111 00000 00111001110 */
>-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
>+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
>+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1, r5 */
>+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1, r5 */

Since for the stxvd2x instruction, the last bit is part of the
register number, these two lines should be merged into:
              || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */

As above, the comment needs to be updated to match.

>+               || (op & 0xfc1ff000) == 0x7c012000)   

This looks just wrong: that masks out most of the secondary opcode
field, so it will match many different instructions.  That cannot
be intended ...


>>+const struct target_desc *
>>+rs6000_nat_target::read_description ()
>>+{
>>+   if (ARCH64())
>>+      return tdesc_powerpc_vsx64;
>>+   else
>>+      return tdesc_powerpc_vsx32;
>>+}
>
>Well, is this true?  Shouldn't this check whether the machine
>actually *has* VSX, and return a different tdesc otherwise?
>
>ANS = AIX 5.3 onwards we get those _vmx_context_t, __power_vmx variables to support these target descriptions. 

This means that on older AIX versions, GDB simply won't work anymore,
right?  If so, I guess I'll leave if up to you to decide whether this
is acceptable.  But the minimum supported version should be documented
somewhere (there's still at least mention of AIX 4.x being supported).
Also, if we do switch the minimum supported version, I think there's
quite a bit of existing code intended to handle old versions that could
then just be removed ...


>>+  if (have_altivec)
>>+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec",
>cb_data);
>>+
>>+  if (have_vsx)
>>+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx",
>cb_data);   
>As those regsets are the same between 32- and 64-bit, they should
>probably be just called rs6000_aix_vrregset etc.
>
>ANS = No, their offsets are different. Hence, we have different variables for them. 

That was maybe a misunderstanding, I agree that vrregset and vsxregset
need to be two different variables.  I was simple suggesting that their
names should not contain "32" unless they are 32-bit specific.

I.e. use rs6000_aix_vrregset and rs6000_aix_vsxregset instead of
rs6000_aix32_vrregset and rs6000_aix32_vsxregset.


>>-   bfd_mach_ppc_620, &tdesc_powerpc_64},
>>+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},
>
>Should we change the default for "Motorola PowerPC 620"
>at this stage?  Can we even test on that machine?
>ANS = No. No we cannot test on that machine. 

Well, why are you changing it then?  Shouldn't those
defaults be left as they are, and only be overridden
on platforms where we know we have support (which
should be done by rs6000_nat_target::read_description).


Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2022-10-28 12:39     ` Ulrich Weigand
@ 2022-11-14 16:26       ` Aditya Kamath1
  2022-11-15 19:03         ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2022-11-14 16:26 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 14259 bytes --]

Hi Ulrich,

Thank you for the feedback. Please find attached the new patch. [See: 0001-Enable-Vector-instruction-debugging-support-for-AIX.patch ]

Kindly let me know if any changes required.

I have answered point by point for the feedback below. Please find below.

Have a nice day ahead.

Thanks and regards,
Aditya.

--------------------------------
>I just noticed that there seem to be two methods, handling
>user threads and kernel threads, respectively.  You patch
>only adds support for VMX/VSX registers to kernel threads
>-- should this also be done for user threads?  (Same applies
>to store_regs_... of course.)

Yes, this I have added in the new patch..

>>+  /* vector registers.  */
>>+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)

>This check isn't quite correct.  I think it should be:
 > if the target has vector registers
 > and (all registers are requested, i.e. regno == -1
  >     or a vector register is requested, i.e. regno is a VR)
>
>Something along these lines:
 >if (tdep->ppc_vr0_regnum != -1 && tdep->vrsave_regnum != -1
  >   && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
  >                       && regno <= tdep->ppc_vrsave_regnum))

Yes, this I have added in the new patch..

>So if access to VMX registers fails because ptrace fails,
>you now zero out the registers.  But if access fails because
>__power_vmx() fails, the registers are left undefined.

>Is this intentional?  What the meaning of this difference?

So, if VMX register fails I will get an output like this below. Otherwise, I set to 0 like it is in all other places. So I am not doing any special handling..


(gdb) info reg vr0

vr0            {uint128 = <unavailable>, v4_float = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v4_int32 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v8_int16 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>}, v16_int8 = {<unavailable> <repeats 16 times>}}


>Is there a reason for not using &(vmx->__vr[regno]) like above?
>That would seem to be more straightforward.
This I have changed in the patch.. No reasons..

>>+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
>>+    else
>>+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);

>Just noticed this here.  Everywhere else in this file, a *pid* is
>passed to rs6000_ptrace64/32.  Only in this new routine, you're
>apparently passing a thread ID.   Why should this be different just
>for these registers?  Shouldn't per-thread registers be handled in
>aix-thread.c anyway?

Well, this is because in the documentation I read, I did not find something like a PT_READ_VSX that I can use. All I have is PTT_READ_VSX and in AIX PTT _* options are usually thread IDs.. I am restricted.. If it existed, I would have loved to use it. Like for writing general purpose registers we have PTT_WRITE_GPRS and PT_WRITE_GPRS and can use it as per convenience of thread or process..

>>+
>>+  fetch_altivec_registers_aix (regcache);
>>+  fetch_vsx_registers_aix (regcache);
>> }


>I think you should call this only if the requested regno
>actually *is* a VMX or VSX register.  Also, if this is the
>case, you don't need to do anything else in this routine.
>This should be separate checks at the beginning of the
>routine, just like you now do in store_register.

I have taken care of it in the new patch..

>>+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4, SIMM */

>Please fix the tabs vs. spaces, and keep the comments at the end aligned.

>>More importantly, the code doesn't match the comment before the if
>>any more.  This now accepts many other "li" variants, and even a few
>>"addi" that aren't actually "li" (it only verifies four out of the
>>five bits of "RA" - for "li" they must all be zero).

>>+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1, r5 */
>>+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1, r5 */

>Since for the stxvd2x instruction, the last bit is part of the
>register number, these two lines should be merged into:
 >             || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */

>As above, the comment needs to be updated to match.

>>+               || (op & 0xfc1ff000) == 0x7c012000)

>This looks just wrong: that masks out most of the secondary opcode
>field, so it will match many different instructions.  That cannot
>be intended ...

I realised this wasn't required while I experiment. I got your point..

>This means that on older AIX versions, GDB simply won't work anymore,
>right?  If so, I guess I'll leave if up to you to decide whether this
>is acceptable.  But the minimum supported version should be documented
>somewhere (there's still at least mention of AIX 4.x being supported).
>Also, if we do switch the minimum supported version, I think there's
>quite a bit of existing code intended to handle old versions that could
>then just be removed ...

How would you like me to document this. Let me know.. And we can work out if possible, via another patch to remove handling the old version codes.

>Should we change the default for "Motorola PowerPC 620"
>at this stage?  Can we even test on that machine?
>>ANS = No. No we cannot test on that machine.

>Well, why are you changing it then?  Shouldn't those
>defaults be left as they are, and only be overridden
>on platforms where we know we have support (which
>should be done by rs6000_nat_target::read_description).

I have removed the same in this patch...


________________________________
From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Sent: 28 October 2022 18:09
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>; Aditya Kamath1 <Aditya.Kamath1@ibm.com>; simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Thank you for the feedback. Please find attached the new patch.

Thanks for the update!  Please find additional comments below.

>Kindly let me know if any changes required.

>@@ -1352,6 +1352,43 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,

I just noticed that there seem to be two methods, handling
user threads and kernel threads, respectively.  You patch
only adds support for VMX/VSX registers to kernel threads
-- should this also be done for user threads?  (Same applies
to store_regs_... of course.)

>+  /* vector registers.  */
>+  if (tdep->ppc_vr0_regnum != -1 && regno >= tdep->ppc_vr0_regnum)

This check isn't quite correct.  I think it should be:
  if the target has vector registers
  and (all registers are requested, i.e. regno == -1
       or a vector register is requested, i.e. regno is a VR)

Something along these lines:
 if (tdep->ppc_vr0_regnum != -1 && tdep->vrsave_regnum != -1
     && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
                         && regno <= tdep->ppc_vrsave_regnum))

(Similar for VSX.  Also applies to the store_regs_... code.)

>+      if (__power_vmx())
>+      {
>+        if (arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        if (ret < 0)
>+          memset(&vmx, 0, sizeof(__vmx_context_t));
>+        for (i = 0; i < num_of_vrregs; i++)
>+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
>+      }

So if access to VMX registers fails because ptrace fails,
you now zero out the registers.  But if access fails because
__power_vmx() fails, the registers are left undefined.

Is this intentional?  What the meaning of this difference?

>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
>+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
>+                                 &(vmx->__vr[0]) + regno);

Is there a reason for not using &(vmx->__vr[regno]) like above?
That would seem to be more straightforward.

>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;
>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx())
>+  {
>+    if (ARCH64 ())
>+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
>+    else
>+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);

Just noticed this here.  Everywhere else in this file, a *pid* is
passed to rs6000_ptrace64/32.  Only in this new routine, you're
apparently passing a thread ID.   Why should this be different just
for these registers?  Shouldn't per-thread registers be handled in
aix-thread.c anyway?

>@@ -233,7 +411,7 @@ fetch_register (struct regcache *regcache, int regno)
>            *addr = buf;
>        }
>     }
>-
>+
>   if (!errno)
>     regcache->raw_supply (regno, (char *) addr);
>   else

Please remove these no-op changes from the patch.

>@@ -244,6 +422,9 @@ fetch_register (struct regcache *regcache, int regno)
> #endif
>       errno = 0;
>     }
>+
>+  fetch_altivec_registers_aix (regcache);
>+  fetch_vsx_registers_aix (regcache);
> }


I think you should call this only if the requested regno
actually *is* a VMX or VSX register.  Also, if this is the
case, you don't need to do anything else in this routine.
This should be separate checks at the beginning of the
routine, just like you now do in store_register.

>@@ -1972,7 +1972,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
>       /* 001110 00000 00000 iiii iiii iiii iiii  */
>       /* 001110 01110 00000 iiii iiii iiii iiii  */
>       else if ((op & 0xffff0000) == 0x38000000         /* li r0, SIMM */
>-              || (op & 0xffff0000) == 0x39c00000)     /* li r14, SIMM */
>+              || (op & 0xffff0000) == 0x39c00000     /* li r14, SIMM */
>+               || (op & 0xff0f0000) == 0x38000000)     /* li, r4, SIMM */

Please fix the tabs vs. spaces, and keep the comments at the end aligned.

More importantly, the code doesn't match the comment before the if
any more.  This now accepts many other "li" variants, and even a few
"addi" that aren't actually "li" (it only verifies four out of the
five bits of "RA" - for "li" they must all be zero).

Can you explain what exact set of instructions this is *intended*
to match now, and why?  Then we can figure out what the appropriate
bitmask to implement the check would be.

These checks are difficult enough to understand anyway, so it is
crucially important that the comments explaining them are correct
and match what is being done.  So any change must be accompanied
by a corresponding comment update.


>@@ -1986,7 +1987,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
>        }
>       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */
>       /* 011111 sssss 11111 00000 00111001110 */
>-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
>+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
>+               || (op & 0xfc1fffff) == 0x7c012f99 /* stxvd2x Vs,r1, r5 */
>+               || (op & 0xfc1fffff) == 0x7c012f98 /* stxvd2x vs0, r1, r5 */

Since for the stxvd2x instruction, the last bit is part of the
register number, these two lines should be merged into:
              || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */

As above, the comment needs to be updated to match.

>+               || (op & 0xfc1ff000) == 0x7c012000)

This looks just wrong: that masks out most of the secondary opcode
field, so it will match many different instructions.  That cannot
be intended ...


>>+const struct target_desc *
>>+rs6000_nat_target::read_description ()
>>+{
>>+   if (ARCH64())
>>+      return tdesc_powerpc_vsx64;
>>+   else
>>+      return tdesc_powerpc_vsx32;
>>+}
>
>Well, is this true?  Shouldn't this check whether the machine
>actually *has* VSX, and return a different tdesc otherwise?
>
>ANS = AIX 5.3 onwards we get those _vmx_context_t, __power_vmx variables to support these target descriptions.

This means that on older AIX versions, GDB simply won't work anymore,
right?  If so, I guess I'll leave if up to you to decide whether this
is acceptable.  But the minimum supported version should be documented
somewhere (there's still at least mention of AIX 4.x being supported).
Also, if we do switch the minimum supported version, I think there's
quite a bit of existing code intended to handle old versions that could
then just be removed ...


>>+  if (have_altivec)
>>+   cb (".aix-vmx", 560, 560, &rs6000_aix32_vrregset, "AIX altivec",
>cb_data);
>>+
>>+  if (have_vsx)
>>+   cb (".aix-vsx", 256, 256, &rs6000_aix32_vsxregset, "AIX vsx",
>cb_data);
>As those regsets are the same between 32- and 64-bit, they should
>probably be just called rs6000_aix_vrregset etc.
>
>ANS = No, their offsets are different. Hence, we have different variables for them.

That was maybe a misunderstanding, I agree that vrregset and vsxregset
need to be two different variables.  I was simple suggesting that their
names should not contain "32" unless they are 32-bit specific.

I.e. use rs6000_aix_vrregset and rs6000_aix_vsxregset instead of
rs6000_aix32_vrregset and rs6000_aix32_vsxregset.


>>-   bfd_mach_ppc_620, &tdesc_powerpc_64},
>>+   bfd_mach_ppc_620, &tdesc_powerpc_vsx64},
>
>Should we change the default for "Motorola PowerPC 620"
>at this stage?  Can we even test on that machine?
>ANS = No. No we cannot test on that machine.

Well, why are you changing it then?  Shouldn't those
defaults be left as they are, and only be overridden
on platforms where we know we have support (which
should be done by rs6000_nat_target::read_description).


Bye,
Ulrich


[-- Attachment #2: 0001-Enable-Vector-support-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 25841 bytes --]

From 4572c59a3bce6c66c7cab2d9c66c51dd374632e4 Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Mon, 14 Nov 2022 10:01:40 -0600
Subject: [PATCH] Enable vector instruction debugging for AIX

---
 gdb/aix-thread.c      | 227 ++++++++++++++++++++++++++++++++++++++++++
 gdb/rs6000-aix-nat.c  | 210 +++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-tdep.c | 179 +++++++++++++++++++++++++++++++++
 gdb/rs6000-tdep.c     |   5 +-
 4 files changed, 618 insertions(+), 3 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index e556c153576..b09cc0b044b 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -1259,6 +1259,43 @@ fetch_regs_user_thread (struct regcache *regcache, pthdb_pthread_t pdtid)
   else
     supply_sprs32 (regcache, ctx.iar, ctx.msr, ctx.cr, ctx.lr, ctx.ctr,
 			     ctx.xer, ctx.fpscr);
+
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      int ret = 0;
+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VEC, pdtid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, pdtid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+          memset(&vmx, 0, sizeof(__vmx_context_t));
+        for (i = 0; i < num_of_vrregs; i++)
+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      }
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        int ret = 0;
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VSX, pdtid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VSX, pdtid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          memset(&vsx, 0, sizeof(__vsx_context_t));
+        for (i = 0; i < ppc_num_vshrs; i++)
+          regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+        }
+    }
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from
@@ -1352,6 +1389,47 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	    regcache->raw_supply (tdep->ppc_mq_regnum, (char *) &sprs32.pt_mq);
 	}
     }
+   
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+      && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+      && regno <= tdep->ppc_vrsave_regnum)))  
+    {
+      int ret = 0;
+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+          memset(&vmx, 0, sizeof(__vmx_context_t));
+        for (i = 0; i < num_of_vrregs; i++)
+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      }
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+      && (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
+      && regno <= tdep->ppc_vrsave_regnum))) 
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        int ret = 0;
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          memset(&vsx, 0, sizeof(__vsx_context_t));
+        for (i = 0; i < ppc_num_vshrs; i++)
+          regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+        }
+    }
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from the
@@ -1496,6 +1574,37 @@ fill_sprs32 (const struct regcache *regcache,
     regcache->raw_collect (tdep->ppc_fpscr_regnum, fpscr);
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  int regno;
+
+  for (regno = 0; regno < num_of_vrregs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+                                 &(vmx->__vr[regno]));
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store all registers into pthread PDTID, which doesn't have a kernel
    thread.
 
@@ -1511,6 +1620,7 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
   pthdb_context_t ctx;
   uint32_t int32;
   uint64_t int64;
+  int ret;
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1581,6 +1691,62 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
     error (_("aix-thread: store_registers: "
 	     "pthdb_pthread_setcontext returned %s"),
 	   pd_status2str (status));
+
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VEC, pdtid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, pdtid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch AltiVec registers."));
+            memset(&vmx, 0, sizeof(__vmx_context_t));
+          }
+          fill_altivec(regcache, &vmx);
+          if (arch64)
+            ret = ptrace64aix (PTT_WRITE_VEC, pdtid, (long long) &vmx, 0, 0);
+          else
+            ret = ptrace32 (PTT_WRITE_VEC, pdtid, (long long) &vmx, 0, 0);
+          if (ret < 0)
+            perror_with_name (_("Unable to store AltiVec register."));
+        }
+      }
+    }
+  
+  /* vmx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        if (arch64)
+          ret =  ptrace64aix (PTT_READ_VSX, pdtid, (long long) &vsx, 0, 0);
+        else
+          ret =  ptrace32 (PTT_READ_VSX, pdtid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch VSX registers."));
+            memset(&vsx, 0, sizeof(__vsx_context_t));
+          }
+        }
+        fill_vsx (regcache, &vsx);
+        if (arch64)
+          ret = ptrace64aix (PTT_WRITE_VSX, pdtid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_WRITE_VSX, pdtid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          perror_with_name (_("Unable to store VSX register."));
+      }
+   }
 }
 
 /* Store register REGNO if != -1 or all registers otherwise into
@@ -1602,6 +1768,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   double fprs[ppc_num_fprs];
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
+  int ret = 0; 
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1692,6 +1859,66 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+        && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+        && regno <= tdep->ppc_vrsave_regnum)))
+    {
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (arch64)
+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch AltiVec registers."));
+            memset(&vmx, 0, sizeof(__vmx_context_t)); 
+          }
+          fill_altivec(regcache, &vmx);
+          if (arch64)
+            ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+          else
+            ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+          if (ret < 0)
+            perror_with_name (_("Unable to store AltiVec register."));
+        }
+      }
+    }
+ 
+    /* vmx registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1  && tdep->ppc_vrsave_regnum != -1
+      && (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
+      && regno <= tdep->ppc_vrsave_regnum))) 
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        if (arch64)
+          ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch VSX registers."));
+            memset(&vsx, 0, sizeof(__vsx_context_t)); 
+          }
+        }
+        fill_vsx (regcache, &vsx);
+        if (arch64)
+          ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          perror_with_name (_("Unable to store VSX register."));
+      }
+   } 
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index cb141427696..100636059a4 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -54,6 +54,14 @@
 #include <sys/ldr.h>
 #include <sys/systemcfg.h>
 
+#include <sys/context.h>
+#include <sys/pthdebug.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -91,6 +99,8 @@ class rs6000_nat_target final : public inf_ptrace_target
 
   ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override
@@ -187,6 +197,174 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         warning (_("Unable to fetch VSX registers."));
+         return;
+       }
+    }
+  }
+  regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                       regno - tdep->ppc_vsr0_upper_regnum);
+
+  if (ARCH64 ())
+    ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+  else
+    ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store VSX register."));
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         warning (_("Unable to fetch AltiVec registers."));
+         return;
+       }
+    }
+  }
+
+  regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                - tdep->ppc_vr0_regnum);
+
+  if (ARCH64 ())
+    ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+  else
+    ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+  if (ret < 0)
+     perror_with_name (_("Unable to store AltiVec register."));
+
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    supply_vrregset_aix (regcache, &vmx);      
+  }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+    supply_vsxregset_aix (regcache, &vsx);
+  }
+}
+
 /* Fetch register REGNO from the inferior.  */
 
 static void
@@ -200,6 +378,11 @@ fetch_register (struct regcache *regcache, int regno)
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+    fetch_altivec_registers_aix (regcache);
+  if (vsx_register_p (gdbarch, regno))
+    fetch_vsx_registers_aix (regcache);
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -262,6 +445,17 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -314,7 +508,6 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
   struct gdbarch *gdbarch = regcache->arch ();
   if (regno != -1)
     fetch_register (regcache, regno);
-
   else
     {
       ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
@@ -331,7 +524,13 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
       if (tdep->ppc_fp0_regnum >= 0)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
+      
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) 
+        fetch_altivec_registers_aix (regcache);
 
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+          
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -346,6 +545,15 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+      return tdesc_powerpc_vsx64;
+   else
+      return tdesc_powerpc_vsx32;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index d47974b51d1..e282c90e8cb 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,176 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+                                                   + 32; i++, offset += 8)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i;
+    int offset = 0;
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+                                                  + 32; i++, offset += 8)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+              tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +432,19 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data); 
 }
 
 
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 8b6d666bbe7..7e1c2e3b8ab 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1986,7 +1986,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 	}
       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */      
       /* 011111 sssss 11111 00000 00111001110 */
-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
+      else if ((op & 0xfc1fffff) == 0x7c1f01ce     /* stvx Vs, R31, R0 */
+               || (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */
 	{
 	  if (pc == (li_found_pc + 4))
 	    {
@@ -3474,7 +3475,7 @@ static struct ppc_variant variants[] =
   {"powerpc", "PowerPC user-level", bfd_arch_powerpc,
    bfd_mach_ppc, &tdesc_powerpc_altivec32},
   {"power", "POWER user-level", bfd_arch_rs6000,
-   bfd_mach_rs6k, &tdesc_rs6000},
+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},
   {"403", "IBM PowerPC 403", bfd_arch_powerpc,
    bfd_mach_ppc_403, &tdesc_powerpc_403},
   {"405", "IBM PowerPC 405", bfd_arch_powerpc,
-- 
2.31.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2022-11-14 16:26       ` Aditya Kamath1
@ 2022-11-15 19:03         ` Ulrich Weigand
  2023-02-23 12:49           ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2022-11-15 19:03 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>>I just noticed that there seem to be two methods, handling
>>user threads and kernel threads, respectively.  You patch
>>only adds support for VMX/VSX registers to kernel threads
>>-- should this also be done for user threads?  (Same applies
>>to store_regs_... of course.)
>
>Yes, this I have added in the new patch.. 

So you're now using ptrace here as well.  From what I
understand, this wrong - ptrace can only be used with
kernel threads.  For user threads, registers need to
be retrieved from the context managed by the thread
library and retrieved via pthdb_pthread_context.

Shouldn't the vector registers then also come from there?

Do you have a way to test with using user threads?


>>So if access to VMX registers fails because ptrace fails,
>>you now zero out the registers.  But if access fails because
>>__power_vmx() fails, the registers are left undefined.
>
>>Is this intentional?  What the meaning of this difference?
>
>So, if VMX register fails I will get an output like this below.
>Otherwise, I set to 0 like it is in all other places. So I am
>not doing any special handling..
>
>(gdb) info reg vr0
>vr0            {uint128 = <unavailable>, v4_float = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v4_int32 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v8_int16 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>}, v16_int8 = {<unavailable> <repeats 16 times>}}

I still don't quite understand the intended behavior.  As far
as I can see, there are three possible states:

- The machine doesn't have any vector registers
  (i.e. __power_vmx() returns 0)
- The machine does have vector registers, but the inferior
  process does not use them
  (i.e. __power_vmx() returns 1 but ptrace returns an error)
- The inferior process uses vector registers
  (i.e. no error from ptrace)

What is the intended behavior in those cases?  In particular,
should GDB behave differently between the first and the
second case?  Should GDB not show any vector registers at all,
should it show vector registers as <unavailable>, or should
it show vector registers containing zero?


>>>+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
>>>+    else
>>>+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
>
>>Just noticed this here.  Everywhere else in this file, a *pid* is
>>passed to rs6000_ptrace64/32.  Only in this new routine, you're
>>apparently passing a thread ID.   Why should this be different just
>>for these registers?  Shouldn't per-thread registers be handled in
>>aix-thread.c anyway?
>
>Well, this is because in the documentation I read, I did not find something
>like a PT_READ_VSX that I can use. All I have is PTT_READ_VSX and in AIX
>PTT _* options are usually thread IDs.. I am restricted.. If it existed,
>I would have loved to use it. Like for writing general purpose registers
>we have PTT_WRITE_GPRS and PT_WRITE_GPRS and can use it as per convenience
>of thread or process..

Huh.  This is really strange, and doesn't quite map on the current GDB
implementation.  Everything related to thread IDs is currently done in
the aix-threads.c file.  It seems not really clean to mix this up.

How is this intended to be used?

If we need thread IDs anyway (and apparently we can always get a thread
ID even for a non-threaded process?), should we just use the aix-thread.c
methods for all processes?

As an aside, I don't see any documentation of PTT_READ_VSX either.
Do you know since when this is supported?


>>I think you should call this only if the requested regno
>>actually *is* a VMX or VSX register.  Also, if this is the
>>case, you don't need to do anything else in this routine.
>>This should be separate checks at the beginning of the
>>routine, just like you now do in store_register.
>
>I have taken care of it in the new patch.. 

+  if (altivec_register_p (gdbarch, regno))
+    fetch_altivec_registers_aix (regcache);
+  if (vsx_register_p (gdbarch, regno))
+    fetch_vsx_registers_aix (regcache);

I meant that you should skip everything else in those cases:

  if (altivec_register_p (gdbarch, regno))
    {
      fetch_altivec_registers_aix (regcache);
      return;
    }
  if (vsx_register_p (gdbarch, regno))
    {
      fetch_vsx_registers_aix (regcache);
      return;
    }

just like in store_register.



>>Since for the stxvd2x instruction, the last bit is part of the
>>register number, these two lines should be merged into:
> >             || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */
>
>>As above, the comment needs to be updated to match.

You should still do this (the 0x...e mask, and the comment).

>>This means that on older AIX versions, GDB simply won't work anymore,
>>right?  If so, I guess I'll leave if up to you to decide whether this
>>is acceptable.  But the minimum supported version should be documented
>>somewhere (there's still at least mention of AIX 4.x being supported).
>>Also, if we do switch the minimum supported version, I think there's
>>quite a bit of existing code intended to handle old versions that could
>>then just be removed ...
>
>How would you like me to document this. Let me know.. And we can work
>out if possible, via another patch to remove handling the old version codes. 

Well, at the very least this needs to be announced in the NEWS file.

This still mentions AIX 4 being supported.


>>Should we change the default for "Motorola PowerPC 620"
>>at this stage?  Can we even test on that machine?
>>>ANS = No. No we cannot test on that machine.
>
>I have removed the same in this patch...

There's still this one in there:

   {"power", "POWER user-level", bfd_arch_rs6000,
-   bfd_mach_rs6k, &tdesc_rs6000},
+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},

I don't think this should be needed either.

Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2022-11-15 19:03         ` Ulrich Weigand
@ 2023-02-23 12:49           ` Aditya Kamath1
  2023-02-24 15:26             ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2023-02-23 12:49 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 17789 bytes --]

Hi Ulrich and community,

Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

Please see my comments in blue.

Kindly suggest for changes if needed and review this patch.

Have a nice day ahead.

Thanks and regards,
Aditya.

>So you're now using ptrace here as well.  From what I
>understand, this wrong - ptrace can only be used with
>kernel threads.  For user threads, registers need to
>be retrieved from the context managed by the thread
>library and retrieved via pthdb_pthread_context.

>Shouldn't the vector registers then also come from there?

>Do you have a way to test with using user threads?

Yes. So I did not get this back then. As my learning increased via the threads bug we had just solved I understood what you are trying to tell me here. Kindly see pdc_read_regs () and pdc_write_regs ().
We now do it via pthdb_pthread_context ().

Kindly see code 1 which uses user threads and it sample output 1. It works alright. Even our alti-vec-regs.exp testcase in test suite passes.

>>(gdb) info reg vr0
>>vr0            {uint128 = <unavailable>, v4_float = {<unavailable>, <unavailable>, <unavailable>, >><unavailable>}, v4_int32 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v8_int16 = >>{<unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, >><unavailable>, <unavailable>}, v16_int8 = {<unavailable> <repeats 16 times>}}

>I still don't quite understand the intended behavior.  As far
>as I can see, there are three possible states:

>- The machine doesn't have any vector registers
>  (i.e. __power_vmx() returns 0)
If it doesn’t have we do not do any thing. We do not even say machine does not have any vector registers. Hence no else part to this if condition.

>- The machine does have vector registers, but the inferior
>  process does not use them
 > (i.e. __power_vmx() returns 1 but ptrace returns an error)

In this we intend to show it unavailable. Because till the user uses vector registers it has to be unavailable.

- The inferior process uses vector registers
  (i.e. no error from ptrace)
Here we show the value.

>What is the intended behavior in those cases?  In particular,
>should GDB behave differently between the first and the
>second case?  Should GDB not show any vector registers at all,
>should it show vector registers as <unavailable>, or should
>it show vector registers containing zero?

In Linux I have seen they show a 0, in the second case. So do we also do the same?
When I tried doing so, I can tell you ptrace () did not allow me to write 0 as well in store_vsx_register_aix(), since till user or debugee code actually uses it, it is unavailable. So we cannot write 0 in the ptrace call via PT_WRITE_VEC.

But yeah, we can use this regcache->raw_collect (), set to 0 in GDB data structures and return. We won’t be able to write 0 though through ptrace call in the kernel. This way we can show users it is zero like in the linux world. So shall we do it?


>>>+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
>>>+    else
>>>+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
>
>>>Just noticed this here.  Everywhere else in this file, a *pid* is
>>>passed to rs6000_ptrace64/32.  Only in this new routine, you're
>>>apparently passing a thread ID.   Why should this be different just
>>>for these registers?  Shouldn't per-thread registers be handled in
>>>aix-thread.c anyway?
>>Well, this is because in the documentation I read, I did not find something
>>like a PT_READ_VSX that I can use. All I have is PTT_READ_VSX and in AIX
>>PTT _* options are usually thread IDs.. I am restricted.. If it existed,
>>I would have loved to use it. Like for writing general purpose registers
>>we have PTT_WRITE_GPRS and PT_WRITE_GPRS and can use it as per convenience
>>of thread or process..

>Huh.  This is really strange, and doesn't quite map on the current GDB
>implementation.  Everything related to thread IDs is currently done in
>the aix-threads.c file.  It seems not really clean to mix this up.

>How is this intended to be used?

>If we need thread IDs anyway (and apparently we can always get a thread
>ID even for a non-threaded process?), should we just use the aix-thread.c
>methods for all processes?

The online documentation I read { https://www.ibm.com/docs/en/aix/7.2?topic=p-ptrace-ptracex-ptrace64-subroutine } said The PTT_READ_VEC request reads the vector register state of the specified thread. There is no PT_READ_VEC or any call that takes <pid> to get vector registers in any online or internal documents I searched. So we need a thread ID to fetch vector registers.

Coming to just using aix-thread.c for all process, I did try it today. What is happening is fetch_registers () in aix-thread.c is not getting called after the thread target is set for any debugee that does not use pthreads or is multi threaded once the pthdebug session is established. {Like the program with name “code 2” pasted below this email}. Only while the process is getting born it does call fetch_registers () in the rs6000-aix-nat.c . If we can make the thread target to call fetch_registers () once the thread target is set it will work. But is that correct?

>As an aside, I don't see any documentation of PTT_READ_VSX either.
>Do you know since when this is supported?
From the documentation  I read it is 2009.

+  if (altivec_register_p (gdbarch, regno))
+    fetch_altivec_registers_aix (regcache);
+  if (vsx_register_p (gdbarch, regno))
+    fetch_vsx_registers_aix (regcache);

>I meant that you should skip everything else in those cases:

 > if (altivec_register_p (gdbarch, regno))
 >   {
 >     fetch_altivec_registers_aix (regcache);
>      return;

>just like in store_register.

This is also done.

>>Since for the stxvd2x instruction, the last bit is part of the
>>register number, these two lines should be merged into:
> > >            || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */
>>
>>>As above, the comment needs to be updated to match.

>>You should still do this (the 0x...e mask, and the comment).

I did not get this.. Kindly give me more information.

>Well, at the very least this needs to be announced in the NEWS file.

>This still mentions AIX 4 being supported.

So what is the process and when do we do it. Do we do it after the commit of this patch??

There's still this one in there:
>-   bfd_mach_rs6k, &tdesc_rs6000},
>+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},

>I don't think this should be needed either.
This I have removed.

----------------------------------------------------------
Code 1:-
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>

pthread_barrier_t barrier;

#define NUM_THREADS 3

void *
thread_function (void *arg)
{
  /* This ensures that the breakpoint is only hit after both threads
     are created, so the test can always switch to the non-event
     thread when the breakpoint triggers.  */
  pthread_barrier_wait (&barrier);

  vector int Arr1[5] = {
  { 1, 2, 3, 4 },
  { 11, 22, 33, 44 },
  { 111, 222, 333, 444 },
  { 1111, 2222, 3333, 4444 },
  { 11111, 22222, 33333, 44444 }
};
  vector int Arr2[5] = {
  { 1, 2, 3, 4 },
  { 11, 22, 33, 44 },
  { 111, 222, 333, 444 },
  { 1111, 2222, 3333, 4444 },
  { 11111, 22222, 33333, 44444 }
};
vector int Arr3[5] = {
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 }
};
        printf("Adding Arrays\n");
        Arr3[1] = Arr1[0] + Arr2[0];
        printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);



  while (1); /* break here */
}

int
main (void)
{
  int i;

  alarm (300);

  pthread_barrier_init (&barrier, NULL, NUM_THREADS);

  for (i = 0; i < NUM_THREADS; i++)
    {
      pthread_t thread;
      int res;

      res = pthread_create (&thread, NULL,
                            thread_function, NULL);
      assert (res == 0);
    }

  while (1)
    sleep (1);

  return 0;
}
-----------------------------------------------------
Output with patch:-
Reading symbols from /home/aditya/gdb_tests/vector_thread_test...
(gdb) r
Starting program: /home/aditya/gdb_tests/vector_thread_test
Adding Arrays
Arr3[1] = { 2, 4, 6, 8 }
Adding Arrays
Arr3[1] = { 2, 4, 6, 8 }
Adding Arrays
Arr3[1] = { 2, 4, 6, 8 }
[New Thread 258]
[New Thread 515]
[New Thread 772]

Thread 2 received signal SIGINT, Interrupt.
[Switching to Thread 258]
thread_function (arg=0x0) at /home/aditya/gdb_tests/vector_thread_test.c:63
63        while (1); /* break here */
(gdb) info reg $vr0
vr0            {uint128 = 0x2000000040000000600000008, v4_float = {0x2, 0x4, 0x6, 0x8}, v4_int32 = {0x2, 0x4, 0x6, 0x8}, v8_int16 = {0x0, 0x2, 0x0, 0x4, 0x0, 0x6, 0x0, 0x8}, v16_int8 = {0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x8}}
(gdb) thread 2
[Switching to thread 2 (Thread 258)]
#0  thread_function (arg=
0x0) at /home/aditya/gdb_tests/vector_thread_test.c:63
63        while (1); /* break here */
(gdb) info reg $vr0
vr0            {uint128 = 0x2000000040000000600000008, v4_float = {0x2, 0x4, 0x6, 0x8}, v4_int32 = {0x2, 0x4, 0x6, 0x8}, v8_int16 = {0x0, 0x2, 0x0, 0x4, 0x0, 0x6, 0x0, 0x8}, v16_int8 = {0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x8}}
(gdb)
----------------------------------------
Code 2:-
#include <stdio.h>
int main () {
vector int Arr1[5] = {
  { 1, 2, 3, 4 },
  { 11, 22, 33, 44 },
  { 111, 222, 333, 444 },
  { 1111, 2222, 3333, 4444 },
  { 11111, 22222, 33333, 44444 }
};
vector int Arr2[5] = {
  { 1, 2, 3, 4 },
  { 11, 22, 33, 44 },
  { 111, 222, 333, 444 },
  { 1111, 2222, 3333, 4444 },
  { 11111, 22222, 33333, 44444 }
};
vector int Arr3[5] = {
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 0, 0 }
};
        printf("Adding Arrays\n");
        Arr3[1] = Arr1[2] + Arr2[3];
        printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);
        return 0;
}
------------------------------
Sample output 2:-
Reading symbols from /home/aditya/gdb_tests/vector_lab_test...
(gdb) b main
Breakpoint 1 at 0x1000052c: file /home/aditya/gdb_tests/vector_lab_test.c, line 3.
(gdb) r
Starting program: /home/aditya/gdb_tests/vector_lab_test

Breakpoint 1, main () at /home/aditya/gdb_tests/vector_lab_test.c:3
3       vector int Arr1[5] = {
(gdb) n
10      vector int Arr2[5] = {
(gdb) n

17      vector int Arr3[5] = {
(gdb) n
24              printf("Adding Arrays\n");
(gdb) n
Adding Arrays
25              Arr3[1] = Arr1[2] + Arr2[3];
(gdb)
26              printf("Arr3[1] = { %d, %d, %d, %d }\n", Arr3[1][0], Arr3[1][1], Arr3[1][2], Arr3[1][3]);
(gdb) info reg $vr0
vr0            {uint128 = 0x4c60000098c00000e5200001318, v4_float = {0x4c6, 0x98c, 0xe52, 0x1318}, v4_int32 = {0x4c6, 0x98c, 0xe52, 0x1318}, v8_int16 = {0x0, 0x4c6, 0x0, 0x98c, 0x0, 0xe52, 0x0, 0x1318}, v16_int8 = {0x0, 0x0, 0x4, 0xc6, 0x0, 0x0, 0x9, 0x8c, 0x0, 0x0, 0xe, 0x52, 0x0, 0x0, 0x13, 0x18}}
(gdb)

From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Date: Wednesday, 16 November 2022 at 12:33 AM
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>, Aditya Kamath1 <Aditya.Kamath1@ibm.com>, simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX
Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>>I just noticed that there seem to be two methods, handling
>>user threads and kernel threads, respectively.  You patch
>>only adds support for VMX/VSX registers to kernel threads
>>-- should this also be done for user threads?  (Same applies
>>to store_regs_... of course.)
>
>Yes, this I have added in the new patch..

So you're now using ptrace here as well.  From what I
understand, this wrong - ptrace can only be used with
kernel threads.  For user threads, registers need to
be retrieved from the context managed by the thread
library and retrieved via pthdb_pthread_context.

Shouldn't the vector registers then also come from there?

Do you have a way to test with using user threads?


>>So if access to VMX registers fails because ptrace fails,
>>you now zero out the registers.  But if access fails because
>>__power_vmx() fails, the registers are left undefined.
>
>>Is this intentional?  What the meaning of this difference?
>
>So, if VMX register fails I will get an output like this below.
>Otherwise, I set to 0 like it is in all other places. So I am
>not doing any special handling..
>
>(gdb) info reg vr0
>vr0            {uint128 = <unavailable>, v4_float = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v4_int32 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>}, v8_int16 = {<unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>, <unavailable>}, v16_int8 = {<unavailable> <repeats 16 times>}}

I still don't quite understand the intended behavior.  As far
as I can see, there are three possible states:

- The machine doesn't have any vector registers
  (i.e. __power_vmx() returns 0)
- The machine does have vector registers, but the inferior
  process does not use them
  (i.e. __power_vmx() returns 1 but ptrace returns an error)
- The inferior process uses vector registers
  (i.e. no error from ptrace)

What is the intended behavior in those cases?  In particular,
should GDB behave differently between the first and the
second case?  Should GDB not show any vector registers at all,
should it show vector registers as <unavailable>, or should
it show vector registers containing zero?


>>>+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
>>>+    else
>>>+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
>
>>Just noticed this here.  Everywhere else in this file, a *pid* is
>>passed to rs6000_ptrace64/32.  Only in this new routine, you're
>>apparently passing a thread ID.   Why should this be different just
>>for these registers?  Shouldn't per-thread registers be handled in
>>aix-thread.c anyway?
>
>Well, this is because in the documentation I read, I did not find something
>like a PT_READ_VSX that I can use. All I have is PTT_READ_VSX and in AIX
>PTT _* options are usually thread IDs.. I am restricted.. If it existed,
>I would have loved to use it. Like for writing general purpose registers
>we have PTT_WRITE_GPRS and PT_WRITE_GPRS and can use it as per convenience
>of thread or process..

Huh.  This is really strange, and doesn't quite map on the current GDB
implementation.  Everything related to thread IDs is currently done in
the aix-threads.c file.  It seems not really clean to mix this up.

How is this intended to be used?

If we need thread IDs anyway (and apparently we can always get a thread
ID even for a non-threaded process?), should we just use the aix-thread.c
methods for all processes?

As an aside, I don't see any documentation of PTT_READ_VSX either.
Do you know since when this is supported?


>>I think you should call this only if the requested regno
>>actually *is* a VMX or VSX register.  Also, if this is the
>>case, you don't need to do anything else in this routine.
>>This should be separate checks at the beginning of the
>>routine, just like you now do in store_register.
>
>I have taken care of it in the new patch..

+  if (altivec_register_p (gdbarch, regno))
+    fetch_altivec_registers_aix (regcache);
+  if (vsx_register_p (gdbarch, regno))
+    fetch_vsx_registers_aix (regcache);

I meant that you should skip everything else in those cases:

  if (altivec_register_p (gdbarch, regno))
    {
      fetch_altivec_registers_aix (regcache);
      return;
    }
  if (vsx_register_p (gdbarch, regno))
    {
      fetch_vsx_registers_aix (regcache);
      return;
    }

just like in store_register.



>>Since for the stxvd2x instruction, the last bit is part of the
>>register number, these two lines should be merged into:
> >             || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */
>
>>As above, the comment needs to be updated to match.

You should still do this (the 0x...e mask, and the comment).

>>This means that on older AIX versions, GDB simply won't work anymore,
>>right?  If so, I guess I'll leave if up to you to decide whether this
>>is acceptable.  But the minimum supported version should be documented
>>somewhere (there's still at least mention of AIX 4.x being supported).
>>Also, if we do switch the minimum supported version, I think there's
>>quite a bit of existing code intended to handle old versions that could
>>then just be removed ...
>
>How would you like me to document this. Let me know.. And we can work
>out if possible, via another patch to remove handling the old version codes.

Well, at the very least this needs to be announced in the NEWS file.

This still mentions AIX 4 being supported.


>>Should we change the default for "Motorola PowerPC 620"
>>at this stage?  Can we even test on that machine?
>>>ANS = No. No we cannot test on that machine.
>
>I have removed the same in this patch...

There's still this one in there:

   {"power", "POWER user-level", bfd_arch_rs6000,
-   bfd_mach_rs6k, &tdesc_rs6000},
+   bfd_mach_rs6k, &tdesc_powerpc_vsx32},

I don't think this should be needed either.

Bye,
Ulrich

[-- Attachment #2: 0001-Enable-vector-instruction-debugging-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26339 bytes --]

From a903782a49917e72ba28982d966c3afe696c3a9f Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Thu, 23 Feb 2023 05:57:30 -0600
Subject: [PATCH] Enable vector instruction debugging for AIX

---
 gdb/aix-thread.c      | 254 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 221 ++++++++++++++++++++++++++++++++++++
 gdb/rs6000-aix-tdep.c | 182 ++++++++++++++++++++++++++++++
 gdb/rs6000-tdep.c     |   3 +-
 4 files changed, 658 insertions(+), 2 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 4184c87a92b..4a912c3947a 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -301,7 +301,16 @@ ptrace_check (int req, int id, int ret)
 			req, id, ret, errno);
 	  return ret == -1 ? 0 : 1;
 	}
-      break;
+	break;
+     case PTT_READ_VEC:
+     case PTT_READ_VSX:
+        if (debug_aix_thread)
+            gdb_printf (gdb_stdlog,
+                        "ptrace (%d, %d) = %d (errno = %d)\n",
+                        req, id, ret, errno);
+	if (ret == -1)
+	  return -1;
+	break;
     }
   error (_("aix-thread: ptrace (%d, %d) returned %d (errno = %d %s)"),
 	 req, id, ret, errno, safe_strerror (errno));
@@ -475,6 +484,30 @@ pdc_read_regs (pthdb_user_t user_current_pid,
 	  memcpy (&context->msr, &sprs32, sizeof(sprs32));
 	}
     }  
+
+  /* vector registers.  */
+  __vmx_context_t vmx;
+  if (__power_vmx())
+  {
+    if (data->arch64)
+      if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+    else
+      if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+  }
+
+  /* vsx registers.  */
+  __vsx_context_t vsx;
+  if (__power_vsx())
+  {
+    if (data->arch64)
+      if (!ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+    else
+      if (!ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));  
+  }
   return 0;
 }
 
@@ -531,6 +564,24 @@ pdc_write_regs (pthdb_user_t user_current_pid,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &context->msr, 0, NULL);
 	}
     }
+
+  /* vector registers.  */
+  if (__power_vmx())
+  {
+    if (data->arch64)
+      ptrace64aix (PTT_WRITE_VEC, tid, (unsigned long) &context->vmx, 0, 0);
+    else
+      ptrace32 (PTT_WRITE_VEC, tid, (uintptr_t) &context->vmx, 0, 0);
+  }
+
+  /* vsx registers.  */
+  if (__power_vsx())
+  {
+    if (data->arch64)
+      ptrace64aix (PTT_WRITE_VSX, tid, (unsigned long) &context->vsx, 0, 0);
+    else
+      ptrace32 (PTT_WRITE_VSX, tid, (uintptr_t) &context->vsx, 0, 0);
+  }
   return 0;
 }
 
@@ -1172,6 +1223,34 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   return pd_update (ptid.pid ());
 }
 
+/* Supply AIX altivec registers, both 64 and 32 bit.  */
+
+static void 
+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
+{       
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno; 
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;            
+  for (regno = 0; regno < num_of_vrregs; regno++)
+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno, 
+			   &(vmx.__vr[regno]));
+}
+
+/* Supply AIX VSX registers, both 64 and 32 bit.  */
+
+static void
+supply_vsx_regs (struct regcache *regcache, __vsx_context_t vsx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+     regcache->raw_supply (tdep->ppc_vsr0_regnum + regno, 
+                           &(vsx.__vsr_dw1[regno]));
+}
+
 /* Record that the 64-bit general-purpose registers contain VALS.  */
 
 static void
@@ -1321,6 +1400,12 @@ fetch_regs_user_thread (struct regcache *regcache, pthdb_pthread_t pdtid)
   else
     supply_sprs32 (regcache, ctx.iar, ctx.msr, ctx.cr, ctx.lr, ctx.ctr,
 			     ctx.xer, ctx.fpscr);
+
+  /* Altivec registers.  */
+  supply_altivec_regs (regcache, ctx.vmx);
+
+  /* VSX registers.  */
+  supply_vsx_regs (regcache, ctx.vsx);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from
@@ -1380,6 +1465,43 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	}
     }
 
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      int ret = 0;
+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (data->arch64)
+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
+        if (ret < 0)
+          memset(&vmx, 0, sizeof(__vmx_context_t));
+        for (i = 0; i < num_of_vrregs; i++)
+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      }
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        int ret = 0;
+        if (data->arch64)
+          ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          memset(&vsx, 0, sizeof(__vsx_context_t));
+        for (i = 0; i < ppc_num_vshrs; i++)
+          regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+        }
+    }
+
   /* Floating-point registers.  */
 
   if (ppc_floating_point_unit_p (gdbarch)
@@ -1447,6 +1569,37 @@ aix_thread_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  int regno;
+
+  for (regno = 0; regno < num_of_vrregs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+                                 &(vmx->__vr[regno]));
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store the gp registers into an array of uint32_t or uint64_t.  */
 
 static void
@@ -1582,6 +1735,10 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
   uint64_t int64;
   struct aix_thread_variables *data;
   data = get_thread_data_helper_for_ptid (inferior_ptid);
+  int ret;
+  __vmx_context_t *vmx;
+  __vsx_context_t  *vsx;
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1594,6 +1751,40 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
 	   pd_status2str (status));
 
+  /* Fill altivec-registers.  */
+
+  if (__power_vmx())
+  {
+    memset(&vmx, 0, sizeof(__vmx_context_t));
+    if (data->arch64)
+    {
+      for (i = 0; i < num_of_vrregs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vmx->__vr[i])); 
+	    ctx.vmx.__vr[i] = vmx->__vr[i]; 
+	  }
+    }
+  }
+
+  /* Fill vsx registers. */
+
+  if (__power_vsx())
+  {
+    memset(&vsx, 0, sizeof(__vsx_context_t));
+    if (data->arch64)
+    {
+      for (i = 0; i < ppc_num_vshrs; i++)
+	 if (REG_VALID == regcache->get_register_status (tdep->ppc_vsr0_regnum + i))
+	 {
+	   regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));  
+            ctx.vsx.__vsr_dw1[i] = vsx->__vsr_dw1[i];
+	 } 
+    }
+  }
+
   /* Collect general-purpose register values from the regcache.  */
 
   for (i = 0; i < ppc_num_gprs; i++)
@@ -1674,6 +1865,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
   struct aix_thread_variables *data;
+  int ret = 0;
 
   data = get_thread_data_helper_for_ptid (regcache->ptid ());
 
@@ -1766,6 +1958,66 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+        && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+        && regno <= tdep->ppc_vrsave_regnum)))
+    {
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+        if (data->arch64)
+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        else
+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch AltiVec registers."));
+            memset(&vmx, 0, sizeof(__vmx_context_t)); 
+          }
+          fill_altivec(regcache, &vmx);
+          if (data->arch64)
+            ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+          else
+            ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+          if (ret < 0)
+            perror_with_name (_("Unable to store AltiVec register."));
+        }
+      }
+    }
+
+    /* vmx registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1  && tdep->ppc_vrsave_regnum != -1
+      && (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
+      && regno <= tdep->ppc_vrsave_regnum))) 
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+        if (data->arch64)
+          ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+        {
+          if (errno == ENXIO)
+          {
+            warning (_("Unable to fetch VSX registers."));
+            memset(&vsx, 0, sizeof(__vsx_context_t)); 
+          }
+        }
+        fill_vsx (regcache, &vsx);
+        if (data->arch64)
+          ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        else
+          ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+        if (ret < 0)
+          perror_with_name (_("Unable to store VSX register."));
+      }
+   }  
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index 8c9dc1a6e68..1911d8f768e 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -58,6 +58,15 @@
 #include <procinfo.h>
 #include <sys/types.h>
 
+/* Header files for alti-vec reg.  */
+#include <sys/context.h>
+#include <sys/pthdebug.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -99,6 +108,8 @@ class rs6000_nat_target final : public inf_ptrace_target
      support.  */
   void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override;
@@ -272,6 +283,175 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         warning (_("Unable to fetch VSX registers."));
+         return;
+       }
+    }
+  }
+  regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                       regno - tdep->ppc_vsr0_upper_regnum);
+
+  if (ARCH64 ())
+    ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+  else
+    ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store VSX register."));
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+    {
+       if (errno == ENXIO)
+       {
+         warning (_("Unable to fetch AltiVec registers."));
+         return;
+       }
+    }
+  }
+
+  regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                - tdep->ppc_vr0_regnum);
+
+  if (ARCH64 ())
+    ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+  else
+    ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+  if (ret < 0)
+     perror_with_name (_("Unable to store AltiVec register."));
+
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx())
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    supply_vrregset_aix (regcache, &vmx);
+  }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx())
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+    supply_vsxregset_aix (regcache, &vsx);
+  }
+}
+
 void rs6000_nat_target::post_startup_inferior (ptid_t ptid)
 {
 
@@ -326,6 +506,20 @@ fetch_register (struct regcache *regcache, int regno)
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
 
+  /*Alti-vec register.  */
+  if (altivec_register_p (gdbarch, regno))
+  {
+    fetch_altivec_registers_aix (regcache);
+    return;
+  }
+
+  /*VSX register.  */
+  if (vsx_register_p (gdbarch, regno))
+  {
+    fetch_vsx_registers_aix (regcache);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -388,6 +582,18 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -458,6 +664,12 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
 
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) 
+        fetch_altivec_registers_aix (regcache);
+
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -472,6 +684,15 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+      return tdesc_powerpc_vsx64;
+   else
+      return tdesc_powerpc_vsx32;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 15602c80b00..78d16f2a217 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,178 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+                                                   + 32; i++, offset += 8)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i;
+    int offset = 0;
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+                                                  + 32; i++, offset += 8)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+              tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +434,20 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data); 
+
 }
 
 
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 592b447948e..a976cc6a3b3 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1986,7 +1986,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 	}
       /* Store vector register S at (r31+r0) aligned to 16 bytes.  */      
       /* 011111 sssss 11111 00000 00111001110 */
-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
+		|| (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */
 	{
 	  if (pc == (li_found_pc + 4))
 	    {
-- 
2.38.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-02-23 12:49           ` Aditya Kamath1
@ 2023-02-24 15:26             ` Ulrich Weigand
  2023-03-01 12:34               ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2023-02-24 15:26 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>>So you're now using ptrace here as well.  From what I
>>understand, this wrong - ptrace can only be used with
>>kernel threads.  For user threads, registers need to
>>be retrieved from the context managed by the thread
>>library and retrieved via pthdb_pthread_context.
>
>>Shouldn't the vector registers then also come from there?
>
>>Do you have a way to test with using user threads?
>
>Yes. So I did not get this back then. As my learning increased via
>the threads bug we had just solved I understood what you are trying
>to tell me here. Kindly see pdc_read_regs () and pdc_write_regs (). 

I notice that the other registers are guarded via
PTHDB_FLAG_GPRS and similar flags.  Is there not any
equivalent flag for VMX / VSX registers?


>>I still don't quite understand the intended behavior.  As far
>>as I can see, there are three possible states:
>
>>- The machine doesn't have any vector registers
>>  (i.e. __power_vmx() returns 0)
>If it doesn’t have we do not do any thing. We do not even say machine does
>not have any vector registers. Hence no else part to this if condition. 

Well, but in your new rs6000_nat_target::read_description
routine, you *do* in fact say that *every* machine always
has VMX and VSX registers.

If you want those registers to simply not be present at
all on machines that do not have them, read_description
should choose an appropriate regset based on __power_vmx
and __power_vsx.

>>What is the intended behavior in those cases?  In particular,
>>should GDB behave differently between the first and the
>>second case?  Should GDB not show any vector registers at all,
>>should it show vector registers as <unavailable>, or should
>>it show vector registers containing zero?
>
>In Linux I have seen they show a 0, in the second case.
>So do we also do the same? When I tried doing so, I can tell
>you ptrace () did not allow me to write 0 as well in
>store_vsx_register_aix(), since till user or debugee code
>actually uses it, it is unavailable. So we cannot write 0
>in the ptrace call via PT_WRITE_VEC. 

I think this is different between AIX and Linux then.  If
you cannot write anything to the register, I agree it makes
sense to show it as "unavailable".


>>Huh.  This is really strange, and doesn't quite map on the current GDB
>>implementation.  Everything related to thread IDs is currently done in
>>the aix-threads.c file.  It seems not really clean to mix this up.
>
>>How is this intended to be used?
>
>>If we need thread IDs anyway (and apparently we can always get a thread
>>ID even for a non-threaded process?), should we just use the aix-thread.c
>>methods for all processes?

>The online documentation I read { https://www.ibm.com/docs/en/aix/7.2?topic=p-ptrace-ptracex-ptrace64-subroutine }
>said The PTT_READ_VEC request reads the vector register state of the
>specified thread. There is no PT_READ_VEC or any call that takes <pid>
>to get vector registers in any online or internal documents I searched.
>So we need a thread ID to fetch vector registers. 

I see.  Still, the rs6000-aix-nat.c routines should only be called
for single-threaded processes, right?  For these processes, does the
kernel thread ID come from a different name space as the process ID,
or are those IDs just the same (they would be on Linux)?

>Coming to just using aix-thread.c for all process, I did try it today.
>What is happening is fetch_registers () in aix-thread.c is not getting
>called after the thread target is set for any debugee that does not use
>pthreads or is multi threaded once the pthdebug session is established.
>{Like the program with name “code 2” pasted below this email}. Only while
>the process is getting born it does call fetch_registers () in the
>rs6000-aix-nat.c . If we can make the thread target to call
>fetch_registers () once the thread target is set it will work.
>But is that correct?

What's supposed to happen is that for single-threaded processes,
fetch_registers in rs6000-aix-nat.c is called; while for multi-
threaded processes the routine in aix-thread.c is called.  The
latter will handle either user threads or kernel threads.

Looking at the big picture, I think the best way to remove the
duplication would be to move all handling of *kernel* threads
to rs6000-aix-nat.c, and leave only user threads in aix-threads.c.

That would mean using all three fields in ptid_t:
- pid should hold the pid
- lwp should hold the kernel thread ID (tid_t or pthdb_tid_t)
- tid should hold the user thread ID (pthdb_pthread_t)

That would match the Linux precedent, and would allow all
ptrace-related access to be done completely in rs6000-aix-nat.c
(using the lwp / tid_t for register access), and leave only
the context-based user thread access in aix-threads.c.

But I guess this could be done as a future cleanup.

>>>Since for the stxvd2x instruction, the last bit is part of the
>>>register number, these two lines should be merged into:
>> > >            || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */
>>>
>>>>As above, the comment needs to be updated to match.
>
>>>You should still do this (the 0x...e mask, and the comment).
>
>I did not get this.. Kindly give me more information. 

Right now in this line you're trying to add:
+               || (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */
the code does not match the comment.

As I do not know why you're making this change in the
first place, I cannot tell whether the code is correct
and the comment is wrong or vice versa. (Or maybe neither
is fully correct?)

Looking at the ISA document, we see this documentation
of the stxvd2x instruction:

  stxvd2x XS,RA,RB

  bit  0- 5: constant 31
  bit  6-10: S
  bit 11-15: RA
  bit 16-20: RB
  bit 21-30: constant 972
  bit 31:    SX

where RA and RB are 5-bit GPR numbers (0..31), while
XS is a 6-bit VSX register number (0..63), split into
the highest bit SX and the low 5 bits S.

If you want to match this instruction, you'll have to
verify that the two constant fields have the expected
value.  If you also want to restrict the match to certain
values or ranges for the RA, RB, and XS register numbers,
you have to match those as well.  This is where the current
masking / comparsion looks inconsistent to me.

Splitting your mask and comparison values up into the
bit fields are defined above, we have:

  mask:       0xfc1fffff
  comparison: 0x7c012f98

  bit  0- 5: mask all ones  - comparison 31
  bit  6-10: mask all zeros - comparison 0
  bit 11-15: mask all ones  - comparison 1
  bit 16-20: mask all ones  - comparison 5
  bit 21-30: mask all ones  - comparison 972
  bit 31:    mask all ones  - comparison 0

So, this enforces that the constant fields have the
correct values (good).  It also enforces that RA == 1
and RB == 5.  I guess this at least matches the comment,
but I do not understand the reason for matching just
this register combination.  (I guess RA == 1 is supposed
to match the stack pointer, but why RB == 5 ?)

However, where it gets weird is the XS field:  the
comment says it looks only for VS0.  But the test
actually allows many more vector registers here:
specifically, it allows any value for the low 5 bits,
and forces the high bit to zero. This means that the
test will match for VSX registers 0..32, but not for
VSX registers 33..63.  This seems strange.

Again, my primary question would be, why are you making
this change at all?  Based on that, what is the exact
set of possible instructions you want to match here?
Given that, it should be straightforward to construct
the correct mask / comparison values to implement that
choice.

>>Well, at the very least this needs to be announced in the NEWS file.
>
>>This still mentions AIX 4 being supported.
>
>So what is the process and when do we do it. Do we do it
>after the commit of this patch?? 

I think as part of this patch, you should update the NEWS
file with the supported AIX versions going forward.

(Note that it would be good to actually verify that the
debugger builds and works correctly on all the versions
that we declare as supported.)

Some additional comments on the patch:

>+  /* vector registers.  */
>+  __vmx_context_t vmx;
>+  if (__power_vmx())
>+  {
>+    if (data->arch64)
>+      if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
>+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
>+    else
>+      if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
>+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
>+  }

The other registers are filled with zeros if ptrace fails,
why not here?

>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;            
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno, 
>+			   &(vmx.__vr[regno]));

Not sure about the contents of the vmx structure, but I'm
wondering if this is correct for the VRSAVE and VSCR
registers.  Are they part of the __vr array, or are they
in separate fields?

>+  for (regno = 0; regno < ppc_num_vshrs; regno++)
>+     regcache->raw_supply (tdep->ppc_vsr0_regnum + regno, 
>+                           &(vsx.__vsr_dw1[regno]));

This should only supply ppc_vsr0_upper_regnum etc.  (upper halves)
not the full vsr0.

 
>+      if (__power_vmx())
>+      {
>+        if (data->arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
>+        if (ret < 0)
>+          memset(&vmx, 0, sizeof(__vmx_context_t));
>+        for (i = 0; i < num_of_vrregs; i++)
>+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
>+      }

This is strange - if ptrace fails, the fields are zeroed, but if
__power_vmx is false, they're just left uninitialized.  What is
even the point of the __power_vmx check in the first place here?^

>+  int ret;
>+  __vmx_context_t *vmx;
>+  __vsx_context_t  *vsx;
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
> 
>   if (debug_aix_thread)
>     gdb_printf (gdb_stdlog, 
>@@ -1594,6 +1751,40 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
>     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
> 	   pd_status2str (status));
> 
>+  /* Fill altivec-registers.  */
>+
>+  if (__power_vmx())
>+  {
>+    memset(&vmx, 0, sizeof(__vmx_context_t));

This is wrong, and a serious memory corruption.  If you do this, vmx 
needs to be declared as __vmx_context_t, not __vmx_context_t *.

>+      if (__power_vmx())
>+      {
>+        if (data->arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        if (ret < 0)
>+        {
>+          if (errno == ENXIO)
>+          {
>+            warning (_("Unable to fetch AltiVec registers."));
>+            memset(&vmx, 0, sizeof(__vmx_context_t)); 
>+          }
>+          fill_altivec(regcache, &vmx);
>+          if (data->arch64)
>+            ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
>+          else
>+            ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);

Huh?  So you update with new values only if reading the old values
*failed*?  That logic looks clearly wrong here.

>+/* Header files for alti-vec reg.  */
>+#include <sys/context.h>
>+#include <sys/pthdebug.h>

Do you really need pthdebug.h here?  Even if we need to handle threads
here, it will only be *kernel* threads, so this shouldn't be needed.

>+  tid64_t  thrd_i = 0;
>+
>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;

So if this call fails, thrd_i just remains 0?  How does this
work, or what's the point of this?

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+      return tdesc_powerpc_vsx64;
>+   else
>+      return tdesc_powerpc_vsx32;
>+}

See above - I think this needs to check whether we actually have
VMX and/or VSX registers.

>-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
>+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
>+		|| (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */

See discussion above.

Also, please ensure you're following the GNU coding style
throughout, and consistently follow the whitespace rules
(tab instead of 8 spaces; no whitespace at end of line).


Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-02-24 15:26             ` Ulrich Weigand
@ 2023-03-01 12:34               ` Aditya Kamath1
  2023-03-03 14:59                 ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2023-03-01 12:34 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 23919 bytes --]

Hi Ulrich and community,

Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

Please see my reply to your comments marked in blue.

Kindly suggest for changes if needed and review this patch.

Have a nice day ahead.

Thanks and regards,
Aditya.

>I notice that the other registers are guarded via
>PTHDB_FLAG_GPRS and similar flags.  Is there not any
>equivalent flag for VMX / VSX registers?

In the pthdebug.h file I don’t see anything available for VMX. I can see PTHDB_FLAG_VSRS but not sure if this is correct. However I have seen parts of GDB use PTHDB_FLAG_REGS in aix-thread file that allows all registers. I have used the same. Kindly see it in the patch.

>>>- The machine doesn't have any vector registers
>>>  (i.e. __power_vmx() returns 0)
>>If it doesn’t have we do not do any thing. We do not even say machine does
>>not have any vector registers. Hence no else part to this if condition.

>Well, but in your new rs6000_nat_target::read_description
>routine, you *do* in fact say that *every* machine always
>has VMX and VSX registers.

>If you want those registers to simply not be present at
>all on machines that do not have them, read_description
>should choose an appropriate regset based on __power_vmx
>and __power_vsx.

I have done these changes in read_description in rs6000-aix-nat.c. Kindly let me know what you think.

>>In Linux I have seen they show a 0, in the second case.
>>So do we also do the same? When I tried doing so, I can tell
>>you ptrace () did not allow me to write 0 as well in
>>store_vsx_register_aix(), since till user or debugee code
>>actually uses it, it is unavailable. So we cannot write 0
>>in the ptrace call via PT_WRITE_VEC.

>I think this is different between AIX and Linux then.  If
>you cannot write anything to the register, I agree it makes
>sense to show it as "unavailable".

Inorder to keep it standardised I have decided to keep it to 0 till debugee uses it, reason being in certain places we are setting vmx variable to 0 in case ptrace fails. It will be better if we keep it uniform throughout. In this patch I have taken care of the same. Kindly let me know what you think

>>The online documentation I read { https://www.ibm.com/docs/en/aix/7.2?topic=p-ptrace-ptracex-ptrace64-subroutine }
>>said The PTT_READ_VEC request reads the vector register state of the
>>specified thread. There is no PT_READ_VEC or any call that takes <pid>
>>to get vector registers in any online or internal documents I searched.
>>So we need a thread ID to fetch vector registers.

>I see.  Still, the rs6000-aix-nat.c routines should only be called
>for single-threaded processes, right?  For these processes, does the
>kernel thread ID come from a different name space as the process ID,
>or are those IDs just the same (they would be on Linux)?

Yes, only for single threaded process. They are of a different name space. The main thread has a kernel thread ID which is not equal to its process ID. I also read in a document that the TID’s in AIX are always odd with the last bit set and PID’s are always even with the last bit set as 0.

>What's supposed to happen is that for single-threaded processes,
>fetch_registers in rs6000-aix-nat.c is called; while for multi-
>threaded processes the routine in aix-thread.c is called.  The
>latter will handle either user threads or kernel threads.

>Looking at the big picture, I think the best way to remove the
>duplication would be to move all handling of *kernel* threads
>to rs6000-aix-nat.c, and leave only user threads in aix-threads.c.

>But I guess this could be done as a future cleanup.

Yes, I felt that we need to do this. We will do it as a separate patch post this vector submission. Two things I need to do is contribute that info sharedlib test case of threads to the community and this clean up. After this patch we will work on these two.

>Right now in this line you're trying to add:
>+               || (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */
>the code does not match the comment.

>Again, my primary question would be, why are you making
>this change at all?  Based on that, what is the exact
>set of possible instructions you want to match here?
>Given that, it should be straightforward to construct
>the correct mask / comparison values to implement that
>choice.

I get what you have explained to me here. It seems this might be the instruction generated in the prologue in certain cases. However I have not succeeded in producing any example that has this in the prologue and do not know the cases. Hence I have removed the same from this patch. Having said, if ever I see it in future in any example we can add it and work around. At this moment it is removed from the patch.  I have tested this with single thread codes and multi-threads and so far no difference of this check existing or not since it is not there in the prologue.

>>Well, at the very least this needs to be announced in the NEWS file.
>
>>This still mentions AIX 4 being supported.
>
>So what is the process and when do we do it. Do we do it
>after the commit of this patch??

>I think as part of this patch, you should update the NEWS
>file with the supported AIX versions going forward.

I have added the same in this patch. Let me know if it is okay.

>(Note that it would be good to actually verify that the
>debugger builds and works correctly on all the versions
>that we declare as supported.)

I will check this and reply in the next email. Will confirm this once I have done it.

>+  /* vector registers.  */
>+  __vmx_context_t vmx;
>+  if (__power_vmx())
>+  {
>+    if (data->arch64)
>+      if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
>+      memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
>+    else
>+      if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
>+      memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
>+  }

>The other registers are filled with zeros if ptrace fails,
>why not here?

This is done.

>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
>+                         &(vmx.__vr[regno]));

Not sure about the contents of the vmx structure, but I'm
wondering if this is correct for the VRSAVE and VSCR
registers.  Are they part of the __vr array, or are they
in separate fields?

They are in separate field.
So the context.h file has the following definition,
typedef struct __vmx_context {
        __vmxreg_t      __vr[32];       /* vector registers               */
        unsigned int    __pad1[3];      /* reserved, must be set to 0     */
        unsigned int    __vscr;         /* vector status and control reg  */
        unsigned int    __vrsave;       /* vrsave special purpose reg     */
        unsigned int    __pad2[3];      /* reserved, must be set to 0     */
} __vmx_context_t;

I have added them in patch as well. Kindly see it. Thank you for pointing out. I have handled them as well. Since there is no  ppc_vscr_regnum for vscr while using supply or collect function,  I used regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr)); to supply it. I saw that tdep->ppc_vrsave_regnum is the last altivec register in the header file and VSCR is one but last i.e. second last. So used it in that form.

>+  for (regno = 0; regno < ppc_num_vshrs; regno++)
>+     regcache->raw_supply (tdep->ppc_vsr0_regnum + regno,
>+                           &(vsx.__vsr_dw1[regno]));

>This should only supply ppc_vsr0_upper_regnum etc.  (upper halves)
>not the full vsr0.

This is done.

>+      if (__power_vmx())
>+      {
>+        if (data->arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
>+        if (ret < 0)
>+          memset(&vmx, 0, sizeof(__vmx_context_t));
>+        for (i = 0; i < num_of_vrregs; i++)
>+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
>+      }

>This is strange - if ptrace fails, the fields are zeroed, but if
>__power_vmx is false, they're just left uninitialized.  What is
>even the point of the __power_vmx check in the first place here?^

This is done. I have removed it. It is not required here, you were right.

>+  int ret;
>+  __vmx_context_t *vmx;
>+  __vsx_context_t  *vsx;

>This is wrong, and a serious memory corruption.  If you do this, vmx
>needs to be declared as __vmx_context_t, not __vmx_context_t *.

This is done.

>+      if (__power_vmx())
>+      {
>+        if (data->arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        if (ret < 0)
>+        {
>+          if (errno == ENXIO)
>+          {
>+            warning (_("Unable to fetch AltiVec registers."));
>+            memset(&vmx, 0, sizeof(__vmx_context_t));

>Huh?  So you update with new values only if reading the old values
>*failed*?  That logic looks clearly wrong here.

This was a mistake from my end. Appreciate you for pointing it out. Thank you so much. I have corrected the same.


>+#include <sys/pthdebug.h>

>Do you really need pthdebug.h here?  Even if we need to handle threads
>here, it will only be *kernel* threads, so this shouldn't be needed.

I have removed it.

>+  tid64_t  thrd_i = 0;
>+
>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;

>So if this call fails, thrd_i just remains 0?  How does this
>work, or what's the point of this?

I have changed this. Kindly see the changes in this patch.

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+      return tdesc_powerpc_vsx64;
>+   else
>+      return tdesc_powerpc_vsx32;
>+}

>See above - I think this needs to check whether we actually have
>VMX and/or VSX registers.

I have changed this. Kindly see the changes in this patch

Also, please ensure you're following the GNU coding style
throughout, and consistently follow the whitespace rules
(tab instead of 8 spaces; no whitespace at end of line).

I have done this. Thank you for letting me know.

From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Date: Friday, 24 February 2023 at 8:56 PM
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>, Aditya Kamath1 <Aditya.Kamath1@ibm.com>, simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX
Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>>So you're now using ptrace here as well.  From what I
>>understand, this wrong - ptrace can only be used with
>>kernel threads.  For user threads, registers need to
>>be retrieved from the context managed by the thread
>>library and retrieved via pthdb_pthread_context.
>
>>Shouldn't the vector registers then also come from there?
>
>>Do you have a way to test with using user threads?
>
>Yes. So I did not get this back then. As my learning increased via
>the threads bug we had just solved I understood what you are trying
>to tell me here. Kindly see pdc_read_regs () and pdc_write_regs ().

I notice that the other registers are guarded via
PTHDB_FLAG_GPRS and similar flags.  Is there not any
equivalent flag for VMX / VSX registers?


>>I still don't quite understand the intended behavior.  As far
>>as I can see, there are three possible states:
>
>>- The machine doesn't have any vector registers
>>  (i.e. __power_vmx() returns 0)
>If it doesn’t have we do not do any thing. We do not even say machine does
>not have any vector registers. Hence no else part to this if condition.

Well, but in your new rs6000_nat_target::read_description
routine, you *do* in fact say that *every* machine always
has VMX and VSX registers.

If you want those registers to simply not be present at
all on machines that do not have them, read_description
should choose an appropriate regset based on __power_vmx
and __power_vsx.

>>What is the intended behavior in those cases?  In particular,
>>should GDB behave differently between the first and the
>>second case?  Should GDB not show any vector registers at all,
>>should it show vector registers as <unavailable>, or should
>>it show vector registers containing zero?
>
>In Linux I have seen they show a 0, in the second case.
>So do we also do the same? When I tried doing so, I can tell
>you ptrace () did not allow me to write 0 as well in
>store_vsx_register_aix(), since till user or debugee code
>actually uses it, it is unavailable. So we cannot write 0
>in the ptrace call via PT_WRITE_VEC.

I think this is different between AIX and Linux then.  If
you cannot write anything to the register, I agree it makes
sense to show it as "unavailable".


>>Huh.  This is really strange, and doesn't quite map on the current GDB
>>implementation.  Everything related to thread IDs is currently done in
>>the aix-threads.c file.  It seems not really clean to mix this up.
>
>>How is this intended to be used?
>
>>If we need thread IDs anyway (and apparently we can always get a thread
>>ID even for a non-threaded process?), should we just use the aix-thread.c
>>methods for all processes?

>The online documentation I read { https://www.ibm.com/docs/en/aix/7.2?topic=p-ptrace-ptracex-ptrace64-subroutine }
>said The PTT_READ_VEC request reads the vector register state of the
>specified thread. There is no PT_READ_VEC or any call that takes <pid>
>to get vector registers in any online or internal documents I searched.
>So we need a thread ID to fetch vector registers.

I see.  Still, the rs6000-aix-nat.c routines should only be called
for single-threaded processes, right?  For these processes, does the
kernel thread ID come from a different name space as the process ID,
or are those IDs just the same (they would be on Linux)?

>Coming to just using aix-thread.c for all process, I did try it today.
>What is happening is fetch_registers () in aix-thread.c is not getting
>called after the thread target is set for any debugee that does not use
>pthreads or is multi threaded once the pthdebug session is established.
>{Like the program with name “code 2” pasted below this email}. Only while
>the process is getting born it does call fetch_registers () in the
>rs6000-aix-nat.c . If we can make the thread target to call
>fetch_registers () once the thread target is set it will work.
>But is that correct?

What's supposed to happen is that for single-threaded processes,
fetch_registers in rs6000-aix-nat.c is called; while for multi-
threaded processes the routine in aix-thread.c is called.  The
latter will handle either user threads or kernel threads.

Looking at the big picture, I think the best way to remove the
duplication would be to move all handling of *kernel* threads
to rs6000-aix-nat.c, and leave only user threads in aix-threads.c.

That would mean using all three fields in ptid_t:
- pid should hold the pid
- lwp should hold the kernel thread ID (tid_t or pthdb_tid_t)
- tid should hold the user thread ID (pthdb_pthread_t)

That would match the Linux precedent, and would allow all
ptrace-related access to be done completely in rs6000-aix-nat.c
(using the lwp / tid_t for register access), and leave only
the context-based user thread access in aix-threads.c.

But I guess this could be done as a future cleanup.

>>>Since for the stxvd2x instruction, the last bit is part of the
>>>register number, these two lines should be merged into:
>> > >            || (op & 0xfc1ffffe) == 0x7c012f98 /* stxvd2x Vs, r1, r5 */
>>>
>>>>As above, the comment needs to be updated to match.
>
>>>You should still do this (the 0x...e mask, and the comment).
>
>I did not get this.. Kindly give me more information.

Right now in this line you're trying to add:
+               || (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */
the code does not match the comment.

As I do not know why you're making this change in the
first place, I cannot tell whether the code is correct
and the comment is wrong or vice versa. (Or maybe neither
is fully correct?)

Looking at the ISA document, we see this documentation
of the stxvd2x instruction:

  stxvd2x XS,RA,RB

  bit  0- 5: constant 31
  bit  6-10: S
  bit 11-15: RA
  bit 16-20: RB
  bit 21-30: constant 972
  bit 31:    SX

where RA and RB are 5-bit GPR numbers (0..31), while
XS is a 6-bit VSX register number (0..63), split into
the highest bit SX and the low 5 bits S.

If you want to match this instruction, you'll have to
verify that the two constant fields have the expected
value.  If you also want to restrict the match to certain
values or ranges for the RA, RB, and XS register numbers,
you have to match those as well.  This is where the current
masking / comparsion looks inconsistent to me.

Splitting your mask and comparison values up into the
bit fields are defined above, we have:

  mask:       0xfc1fffff
  comparison: 0x7c012f98

  bit  0- 5: mask all ones  - comparison 31
  bit  6-10: mask all zeros - comparison 0
  bit 11-15: mask all ones  - comparison 1
  bit 16-20: mask all ones  - comparison 5
  bit 21-30: mask all ones  - comparison 972
  bit 31:    mask all ones  - comparison 0

So, this enforces that the constant fields have the
correct values (good).  It also enforces that RA == 1
and RB == 5.  I guess this at least matches the comment,
but I do not understand the reason for matching just
this register combination.  (I guess RA == 1 is supposed
to match the stack pointer, but why RB == 5 ?)

However, where it gets weird is the XS field:  the
comment says it looks only for VS0.  But the test
actually allows many more vector registers here:
specifically, it allows any value for the low 5 bits,
and forces the high bit to zero. This means that the
test will match for VSX registers 0..32, but not for
VSX registers 33..63.  This seems strange.

Again, my primary question would be, why are you making
this change at all?  Based on that, what is the exact
set of possible instructions you want to match here?
Given that, it should be straightforward to construct
the correct mask / comparison values to implement that
choice.

>>Well, at the very least this needs to be announced in the NEWS file.
>
>>This still mentions AIX 4 being supported.
>
>So what is the process and when do we do it. Do we do it
>after the commit of this patch??

I think as part of this patch, you should update the NEWS
file with the supported AIX versions going forward.

(Note that it would be good to actually verify that the
debugger builds and works correctly on all the versions
that we declare as supported.)

Some additional comments on the patch:

>+  /* vector registers.  */
>+  __vmx_context_t vmx;
>+  if (__power_vmx())
>+  {
>+    if (data->arch64)
>+      if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
>+      memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
>+    else
>+      if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
>+      memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
>+  }

The other registers are filled with zeros if ptrace fails,
why not here?

>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
>+                         &(vmx.__vr[regno]));

Not sure about the contents of the vmx structure, but I'm
wondering if this is correct for the VRSAVE and VSCR
registers.  Are they part of the __vr array, or are they
in separate fields?

>+  for (regno = 0; regno < ppc_num_vshrs; regno++)
>+     regcache->raw_supply (tdep->ppc_vsr0_regnum + regno,
>+                           &(vsx.__vsr_dw1[regno]));

This should only supply ppc_vsr0_upper_regnum etc.  (upper halves)
not the full vsr0.


>+      if (__power_vmx())
>+      {
>+        if (data->arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
>+        if (ret < 0)
>+          memset(&vmx, 0, sizeof(__vmx_context_t));
>+        for (i = 0; i < num_of_vrregs; i++)
>+          regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
>+      }

This is strange - if ptrace fails, the fields are zeroed, but if
__power_vmx is false, they're just left uninitialized.  What is
even the point of the __power_vmx check in the first place here?^

>+  int ret;
>+  __vmx_context_t *vmx;
>+  __vsx_context_t  *vsx;
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>
>   if (debug_aix_thread)
>     gdb_printf (gdb_stdlog,
>@@ -1594,6 +1751,40 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
>     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
>           pd_status2str (status));
>
>+  /* Fill altivec-registers.  */
>+
>+  if (__power_vmx())
>+  {
>+    memset(&vmx, 0, sizeof(__vmx_context_t));

This is wrong, and a serious memory corruption.  If you do this, vmx
needs to be declared as __vmx_context_t, not __vmx_context_t *.

>+      if (__power_vmx())
>+      {
>+        if (data->arch64)
>+          ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        else
>+          ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+        if (ret < 0)
>+        {
>+          if (errno == ENXIO)
>+          {
>+            warning (_("Unable to fetch AltiVec registers."));
>+            memset(&vmx, 0, sizeof(__vmx_context_t));
>+          }
>+          fill_altivec(regcache, &vmx);
>+          if (data->arch64)
>+            ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
>+          else
>+            ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);

Huh?  So you update with new values only if reading the old values
*failed*?  That logic looks clearly wrong here.

>+/* Header files for alti-vec reg.  */
>+#include <sys/context.h>
>+#include <sys/pthdebug.h>

Do you really need pthdebug.h here?  Even if we need to handle threads
here, it will only be *kernel* threads, so this shouldn't be needed.

>+  tid64_t  thrd_i = 0;
>+
>+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
>+                                            &thrd_i, 1) == 1)
>+    thrd_i = thrdentry.ti_tid;

So if this call fails, thrd_i just remains 0?  How does this
work, or what's the point of this?

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+      return tdesc_powerpc_vsx64;
>+   else
>+      return tdesc_powerpc_vsx32;
>+}

See above - I think this needs to check whether we actually have
VMX and/or VSX registers.

>-      else if ((op & 0xfc1fffff) == 0x7c1f01ce)   /* stvx Vs, R31, R0 */
>+      else if ((op & 0xfc1fffff) == 0x7c1f01ce   /* stvx Vs, R31, R0 */
>+              || (op & 0xfc1fffff) == 0x7c012f98) /* stxvd2x vs0, r1, r5 */

See discussion above.

Also, please ensure you're following the GNU coding style
throughout, and consistently follow the whitespace rules
(tab instead of 8 spaces; no whitespace at end of line).


Bye,
Ulrich

[-- Attachment #2: 0001-Enable-vector-instruction-debugging-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26920 bytes --]

From 1481934ea3a5fa3e5231b975b62da7876918bb9c Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Wed, 1 Mar 2023 06:11:28 -0600
Subject: [PATCH] Enable vector instruction debugging for AIX

---
 gdb/NEWS              |   6 +-
 gdb/aix-thread.c      | 265 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 222 +++++++++++++++++++++++++++++++++++
 gdb/rs6000-aix-tdep.c | 182 +++++++++++++++++++++++++++++
 4 files changed, 672 insertions(+), 3 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 75cd11b204e..aca895a3b15 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,8 @@
 
 *** Changes since GDB 13
 
+* AIX now needs to be of version 5.2 or higher to install GDB.
+
 * Multi-target feature configuration
 
   GDB now supports the individual configuration of remote targets' feature
@@ -7606,10 +7608,10 @@ the possible architectures.
 
 Windows 95, x86 Windows NT			i[345]86-*-cygwin32
 M68K NetBSD					m68k-*-netbsd*
-PowerPC AIX 4.x					powerpc-*-aix*
+PowerPC AIX 5.2 or higher			powerpc-*-aix*
 PowerPC MacOS					powerpc-*-macos*
 PowerPC Windows NT				powerpcle-*-cygwin32
-RS/6000 AIX 4.x					rs6000-*-aix4*
+RS/6000 AIX 5.2 or higher			rs6000-*-aix4*
 
 * New targets
 
diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 4184c87a92b..60c286605e3 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -301,7 +301,16 @@ ptrace_check (int req, int id, int ret)
 			req, id, ret, errno);
 	  return ret == -1 ? 0 : 1;
 	}
-      break;
+	break;
+     case PTT_READ_VEC:
+     case PTT_READ_VSX:
+        if (debug_aix_thread)
+            gdb_printf (gdb_stdlog,
+                        "ptrace (%d, %d) = %d (errno = %d)\n",
+                        req, id, ret, errno);
+	if (ret == -1)
+	  return -1;
+	break;
     }
   error (_("aix-thread: ptrace (%d, %d) returned %d (errno = %d %s)"),
 	 req, id, ret, errno, safe_strerror (errno));
@@ -475,6 +484,42 @@ pdc_read_regs (pthdb_user_t user_current_pid,
 	  memcpy (&context->msr, &sprs32, sizeof(sprs32));
 	}
     }  
+
+  /* vector registers.  */
+  __vmx_context_t vmx;
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+      {
+	if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	  memset (&vmx, 0, sizeof (vmx));
+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+      }
+    else
+      {
+	if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	  memset (&vmx, 0, sizeof (vmx));
+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+      }
+  }
+
+  /* vsx registers.  */
+  __vsx_context_t vsx;
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+    { 
+	if (!ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	  memset (&vsx, 0, sizeof (vsx));
+	memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+    }
+    else
+      {
+	if (!ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	  memset (&vsx, 0, sizeof (vsx));
+	memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+      }  
+  }
   return 0;
 }
 
@@ -531,6 +576,24 @@ pdc_write_regs (pthdb_user_t user_current_pid,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &context->msr, 0, NULL);
 	}
     }
+
+  /* vector registers.  */
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+      ptrace64aix (PTT_WRITE_VEC, tid, (unsigned long) &context->vmx, 0, 0);
+    else
+      ptrace32 (PTT_WRITE_VEC, tid, (uintptr_t) &context->vmx, 0, 0);
+  }
+
+  /* vsx registers.  */
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+      ptrace64aix (PTT_WRITE_VSX, tid, (unsigned long) &context->vsx, 0, 0);
+    else
+      ptrace32 (PTT_WRITE_VSX, tid, (uintptr_t) &context->vsx, 0, 0);
+  }
   return 0;
 }
 
@@ -1172,6 +1235,36 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   return pd_update (ptid.pid ());
 }
 
+/* Supply AIX altivec registers, both 64 and 32 bit.  */
+
+static void 
+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
+{ 
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno; 
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  for (regno = 0; regno < num_of_vrregs; regno++)
+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno, 
+			   &(vmx.__vr[regno]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+}
+
+/* Supply AIX VSX registers, both 64 and 32 bit.  */
+
+static void
+supply_vsx_regs (struct regcache *regcache, __vsx_context_t vsx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+     regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + regno, 
+                           &(vsx.__vsr_dw1[regno]));
+}
+
 /* Record that the 64-bit general-purpose registers contain VALS.  */
 
 static void
@@ -1321,6 +1414,12 @@ fetch_regs_user_thread (struct regcache *regcache, pthdb_pthread_t pdtid)
   else
     supply_sprs32 (regcache, ctx.iar, ctx.msr, ctx.cr, ctx.lr, ctx.ctr,
 			     ctx.xer, ctx.fpscr);
+
+  /* Altivec registers.  */
+  supply_altivec_regs (regcache, ctx.vmx);
+
+  /* VSX registers.  */
+  supply_vsx_regs (regcache, ctx.vsx);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from
@@ -1380,6 +1479,39 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	}
     }
 
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      int ret = 0;
+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+      __vmx_context_t vmx;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
+      if (ret < 0)
+	memset(&vmx, 0, sizeof(__vmx_context_t));
+      for (i = 0; i < num_of_vrregs; i++)
+	regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      int ret = 0;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      if (ret < 0)
+        memset(&vsx, 0, sizeof(__vsx_context_t));
+      for (i = 0; i < ppc_num_vshrs; i++)
+        regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+    }
+
   /* Floating-point registers.  */
 
   if (ppc_floating_point_unit_p (gdbarch)
@@ -1447,6 +1579,43 @@ aix_thread_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+  int regno;
+
+  for (regno = 0; regno < num_of_vrregs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+                                 &(vmx->__vr[regno]));
+
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+  { 
+    regcache->raw_collect (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+    regcache->raw_collect (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+  }
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store the gp registers into an array of uint32_t or uint64_t.  */
 
 static void
@@ -1582,6 +1751,10 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
   uint64_t int64;
   struct aix_thread_variables *data;
   data = get_thread_data_helper_for_ptid (inferior_ptid);
+  int ret;
+  __vmx_context_t vmx;
+  __vsx_context_t  vsx;
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1594,6 +1767,45 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
 	   pd_status2str (status));
 
+  /* Fill altivec-registers.  */
+
+  if (__power_vmx())
+  {
+    memset(&vmx, 0, sizeof(__vmx_context_t));
+    if (data->arch64)
+    {
+      for (i = 0; i < num_of_vrregs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vmx.__vr[i])); 
+	    ctx.vmx.__vr[i] = vmx.__vr[i]; 
+	  }
+      if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+      {
+	ctx.vmx.__vrsave = vmx.__vrsave;
+	ctx.vmx.__vscr = vmx.__vscr;
+      }
+    }
+  }
+
+  /* Fill vsx registers. */
+
+  if (__power_vsx())
+  {
+    memset(&vsx, 0, sizeof(__vsx_context_t));
+    if (data->arch64)
+    {
+      for (i = 0; i < ppc_num_vshrs; i++)
+	 if (REG_VALID == regcache->get_register_status (tdep->ppc_vsr0_regnum + i))
+	 {
+	   regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				      &(vsx.__vsr_dw1[i]));  
+	   ctx.vsx.__vsr_dw1[i] = vsx.__vsr_dw1[i];
+	 } 
+    }
+  }
+
   /* Collect general-purpose register values from the regcache.  */
 
   for (i = 0; i < ppc_num_gprs; i++)
@@ -1674,6 +1886,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
   struct aix_thread_variables *data;
+  int ret = 0;
 
   data = get_thread_data_helper_for_ptid (regcache->ptid ());
 
@@ -1766,6 +1979,56 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+	&& (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+	&& regno <= tdep->ppc_vrsave_regnum)))
+    {
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+	if (data->arch64)
+	  ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+	else
+	  ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret > 0)
+        {
+	  fill_altivec(regcache, &vmx);
+	  if (data->arch64)
+	    ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+	  else
+	    ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+	  if (ret < 0)
+	    perror_with_name (_("Unable to store AltiVec register after read"));
+	}
+      }
+    }
+
+    /* vmx registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1  && tdep->ppc_vrsave_regnum != -1
+	&& (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
+	&& regno <= tdep->ppc_vrsave_regnum))) 
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+	if (data->arch64)
+	  ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	else
+	  ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	if (ret > 0)
+	{
+	  fill_vsx (regcache, &vsx);
+	  if (data->arch64)
+	    ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+	  else
+	    ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+	  if (ret < 0)
+	    perror_with_name (_("Unable to store VSX register after read"));
+	}
+      }
+    } 
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index 8c9dc1a6e68..f8de6f0cf60 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -58,6 +58,14 @@
 #include <procinfo.h>
 #include <sys/types.h>
 
+/* Header files for alti-vec reg.  */
+#include <sys/context.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -99,6 +107,8 @@ class rs6000_nat_target final : public inf_ptrace_target
      support.  */
   void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override;
@@ -272,6 +282,166 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                           &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+    if (ret < 0)
+      return;
+
+    regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                           regno - tdep->ppc_vsr0_upper_regnum);
+
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+    if (ret < 0)
+      perror_with_name (_("Unable to write VSX registers after reading it"));
+  }
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+      return;
+
+    regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                  - tdep->ppc_vr0_regnum);
+
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+      perror_with_name (_("Unable to store AltiVec register after reading it"));
+  }
+
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    supply_vrregset_aix (regcache, &vmx);
+  }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+    supply_vsxregset_aix (regcache, &vsx);
+  }
+}
+
 void rs6000_nat_target::post_startup_inferior (ptid_t ptid)
 {
 
@@ -326,6 +496,20 @@ fetch_register (struct regcache *regcache, int regno)
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
 
+  /*Alti-vec register.  */
+  if (altivec_register_p (gdbarch, regno))
+  {
+    fetch_altivec_registers_aix (regcache);
+    return;
+  }
+
+  /*VSX register.  */
+  if (vsx_register_p (gdbarch, regno))
+  {
+    fetch_vsx_registers_aix (regcache);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -388,6 +572,18 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -458,6 +654,12 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
 
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) 
+        fetch_altivec_registers_aix (regcache);
+
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -472,6 +674,26 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+   {
+     if (__power_vsx ())
+       return tdesc_powerpc_vsx64;
+     else if (__power_vmx ())
+       return tdesc_powerpc_altivec64;
+   }
+   else
+   {
+     if (__power_vsx ())
+       return tdesc_powerpc_vsx32;
+     else if (__power_vmx ())
+       return tdesc_powerpc_altivec32;
+   }
+   return NULL;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 15602c80b00..78d16f2a217 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,178 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+                                                   + 32; i++, offset += 8)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i;
+    int offset = 0;
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+                                                  + 32; i++, offset += 8)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+              tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +434,20 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data); 
+
 }
 
 
-- 
2.38.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-01 12:34               ` Aditya Kamath1
@ 2023-03-03 14:59                 ` Ulrich Weigand
  2023-03-06 13:45                   ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2023-03-03 14:59 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

This should be nearly ready to commit, I've just found a
few minor issues - see below.

Also, please provide commit message.

>--- a/gdb/NEWS
>+++ b/gdb/NEWS
>@@ -3,6 +3,8 @@
> 
> *** Changes since GDB 13
> 
>+* AIX now needs to be of version 5.2 or higher to install GDB.
>+
> * Multi-target feature configuration
> 
>   GDB now supports the individual configuration of remote targets' feature

I think these are usually under a separate section, something like:

 * Removed targets and native configurations

 GDB no longer supports AIX 4.x and AIX 5.1.  The minimum supported
 AIX version is now AIX 5.2.

As a separate note, I see that even AIX 5.2 itself has been out of
support for over 13 years now, so I'm wondering how much sense it
makes to still claim support for this in GDB.  If we're already
deprecating old versions, maybe it would be better to set the
minimum supported version at 6.1 or even 7.1 at this point? 

>@@ -7606,10 +7608,10 @@ the possible architectures.
> 
> Windows 95, x86 Windows NT			i[345]86-*-cygwin32
> M68K NetBSD					m68k-*-netbsd*
>-PowerPC AIX 4.x					powerpc-*-aix*
>+PowerPC AIX 5.2 or higher			powerpc-*-aix*
> PowerPC MacOS					powerpc-*-macos*
> PowerPC Windows NT				powerpcle-*-cygwin32
>-RS/6000 AIX 4.x					rs6000-*-aix4*
>+RS/6000 AIX 5.2 or higher			rs6000-*-aix4*

This describes what was added in GDB 4.18 - I don't think this
section should be retroactively modified.
 
>+static void 
>+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
>+{ 
>+  ppc_gdbarch_tdep *tdep
>+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
>+  int regno; 
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno, 
>+			   &(vmx.__vr[regno]));

Now that you've taken VRSAVE and VSCR separately, this loop now
only needs to execute 32 times, but you still do it 34 times.
I think you should just use ppc_num_vrs instead of this
num_of_vrregs you compute here.

>+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
>+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));

>+  /* vector registers.  */
>+  if (tdep->ppc_vr0_regnum != -1)
>+    {
>+      int ret = 0;
>+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+      __vmx_context_t vmx;
>+      if (data->arch64)
>+	ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+      else
>+	ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
>+      if (ret < 0)
>+	memset(&vmx, 0, sizeof(__vmx_context_t));
>+      for (i = 0; i < num_of_vrregs; i++)
>+	regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));

Same problem here.

>+      regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
>+      regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));

>+static void
>+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
>+{
>+  struct gdbarch *gdbarch = regcache->arch ();
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  int regno;
>+
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
>+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
>+                                 &(vmx->__vr[regno]));

And here.

>+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
>+  { 
>+    regcache->raw_collect (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
>+    regcache->raw_collect (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));

You should separately check VSCR for REG_VALID.

>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;

Same problem here.
 
>+      if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
>+      {
>+	ctx.vmx.__vrsave = vmx.__vrsave;
>+	ctx.vmx.__vscr = vmx.__vscr;

Also should do a separate REG_VALID check.

>@@ -1766,6 +1979,56 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
>+    /* vmx registers.  */
Should be VSX ?
>+    if (tdep->ppc_vsr0_upper_regnum != -1  && tdep->ppc_vrsave_regnum != -1
>+       && (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
>+       && regno <= tdep->ppc_vrsave_regnum))) 

The regno comparison looks inconsistent (lower bound VSX; upper bound VMX).

>+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
>+{
>+  int i;
>+  struct gdbarch *gdbarch = regcache->arch ();
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+
>+  for (i = 0; i < num_of_vrregs; i++)
>+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
>+                                    &(vmx->__vr[i]));

Same loop count problem here.

>+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
>+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));

>+  /*Alti-vec register.  */
Missing space
>+  /*VSX register.  */
Here as well.
 
>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }
Fix coding style ({ should be indented).


Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-03 14:59                 ` Ulrich Weigand
@ 2023-03-06 13:45                   ` Aditya Kamath1
  2023-03-07 10:25                     ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2023-03-06 13:45 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 9541 bytes --]

Hi Ulrich and community,

Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

Kindly push this patch is there are no further changes.

Have a nice day ahead.

Thanks and regards,
Aditya.

 >GDB no longer supports AIX 4.x and AIX 5.1.  The minimum supported
 >AIX version is now AIX 5.2.

>As a separate note, I see that even AIX 5.2 itself has been out of
>support for over 13 years now, so I'm wondering how much sense it
>makes to still claim support for this in GDB.  If we're already
>deprecating old versions, maybe it would be better to set the
>minimum supported version at 6.1 or even 7.1 at this point?

So I connected with my seniors on this. So AIX folks are using 7.1 now. So I have changed this to minimum 7.x.. Kindly see it in this patch. For those who are below 7.1, we are not supporting.

>-RS/6000 AIX 4.x                                       rs6000-*-aix4*
>+RS/6000 AIX 5.2 or higher                     rs6000-*-aix4*

>This describes what was added in GDB 4.18 - I don't think this
>section should be retroactively modified.

This is not modified anymore. Kindly see the patch.

>+static void
>+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
>+{
>+  ppc_gdbarch_tdep *tdep
>+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
>+  int regno;
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
>+                         &(vmx.__vr[regno]));

>Now that you've taken VRSAVE and VSCR separately, this loop now
>only needs to execute 32 times, but you still do it 34 times.
>I think you should just use ppc_num_vrs instead of this
>num_of_vrregs you compute here.
This is done.

>+      if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
>+      {
>+      ctx.vmx.__vrsave = vmx.__vrsave;
>+      ctx.vmx.__vscr = vmx.__vscr;

>Also should do a separate REG_VALID check.
This is done.

>@@ -1766,6 +1979,56 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
>+    /* vmx registers.  */
>Should be VSX ?
Yes. This is done.

>+    if (tdep->ppc_vsr0_upper_regnum != -1  && tdep->ppc_vrsave_regnum != -1
>+       && (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
>+       && regno <= tdep->ppc_vrsave_regnum)))

>The regno comparison looks inconsistent (lower bound VSX; upper bound VMX).
This is done. It was an error.

>+  for (i = 0; i < num_of_vrregs; i++)
>+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
>+                                    &(vmx->__vr[i]));

>Same loop count problem here.

>+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
>+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));

This is done.

>+  /*Alti-vec register.  */
Missing space
>+  /*VSX register.  */
>Here as well.
This is done.

>Fix coding style ({ should be indented).
This is done. I have eliminated all RHS space and aligned the flower brackets wherever I saw it was not aligned.

From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Date: Friday, 3 March 2023 at 8:29 PM
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>, Aditya Kamath1 <Aditya.Kamath1@ibm.com>, simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX
Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

This should be nearly ready to commit, I've just found a
few minor issues - see below.

Also, please provide commit message.

>--- a/gdb/NEWS
>+++ b/gdb/NEWS
>@@ -3,6 +3,8 @@
>
> *** Changes since GDB 13
>
>+* AIX now needs to be of version 5.2 or higher to install GDB.
>+
> * Multi-target feature configuration
>
>   GDB now supports the individual configuration of remote targets' feature

I think these are usually under a separate section, something like:

 * Removed targets and native configurations

 GDB no longer supports AIX 4.x and AIX 5.1.  The minimum supported
 AIX version is now AIX 5.2.

As a separate note, I see that even AIX 5.2 itself has been out of
support for over 13 years now, so I'm wondering how much sense it
makes to still claim support for this in GDB.  If we're already
deprecating old versions, maybe it would be better to set the
minimum supported version at 6.1 or even 7.1 at this point?

>@@ -7606,10 +7608,10 @@ the possible architectures.
>
> Windows 95, x86 Windows NT                    i[345]86-*-cygwin32
> M68K NetBSD                                   m68k-*-netbsd*
>-PowerPC AIX 4.x                                       powerpc-*-aix*
>+PowerPC AIX 5.2 or higher                     powerpc-*-aix*
> PowerPC MacOS                                 powerpc-*-macos*
> PowerPC Windows NT                            powerpcle-*-cygwin32
>-RS/6000 AIX 4.x                                       rs6000-*-aix4*
>+RS/6000 AIX 5.2 or higher                     rs6000-*-aix4*

This describes what was added in GDB 4.18 - I don't think this
section should be retroactively modified.

>+static void
>+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
>+{
>+  ppc_gdbarch_tdep *tdep
>+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
>+  int regno;
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
>+                         &(vmx.__vr[regno]));

Now that you've taken VRSAVE and VSCR separately, this loop now
only needs to execute 32 times, but you still do it 34 times.
I think you should just use ppc_num_vrs instead of this
num_of_vrregs you compute here.

>+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
>+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));

>+  /* vector registers.  */
>+  if (tdep->ppc_vr0_regnum != -1)
>+    {
>+      int ret = 0;
>+      int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+      __vmx_context_t vmx;
>+      if (data->arch64)
>+      ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
>+      else
>+      ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
>+      if (ret < 0)
>+      memset(&vmx, 0, sizeof(__vmx_context_t));
>+      for (i = 0; i < num_of_vrregs; i++)
>+      regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));

Same problem here.

>+      regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
>+      regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));

>+static void
>+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
>+{
>+  struct gdbarch *gdbarch = regcache->arch ();
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+  int regno;
>+
>+  for (regno = 0; regno < num_of_vrregs; regno++)
>+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
>+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
>+                                 &(vmx->__vr[regno]));

And here.

>+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
>+  {
>+    regcache->raw_collect (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
>+    regcache->raw_collect (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));

You should separately check VSCR for REG_VALID.

>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;

Same problem here.

>+      if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
>+      {
>+      ctx.vmx.__vrsave = vmx.__vrsave;
>+      ctx.vmx.__vscr = vmx.__vscr;

Also should do a separate REG_VALID check.

>@@ -1766,6 +1979,56 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
>+    /* vmx registers.  */
Should be VSX ?
>+    if (tdep->ppc_vsr0_upper_regnum != -1  && tdep->ppc_vrsave_regnum != -1
>+       && (regno == -1 || (regno >= tdep->ppc_vsr0_upper_regnum
>+       && regno <= tdep->ppc_vrsave_regnum)))

The regno comparison looks inconsistent (lower bound VSX; upper bound VMX).

>+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
>+{
>+  int i;
>+  struct gdbarch *gdbarch = regcache->arch ();
>+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
>+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
>+
>+  for (i = 0; i < num_of_vrregs; i++)
>+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
>+                                    &(vmx->__vr[i]));

Same loop count problem here.

>+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
>+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));

>+  /*Alti-vec register.  */
Missing space
>+  /*VSX register.  */
Here as well.

>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }
Fix coding style ({ should be indented).


Bye,
Ulrich

[-- Attachment #2: 0001-Enable-vector-instruction-debugging-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26306 bytes --]

From f68dc88d480fd94186348062a841aa15403b3c55 Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Mon, 6 Mar 2023 07:34:14 -0600
Subject: [PATCH] Enable vector instruction debugging for AIX

AIX now supports vector register contents debugging for both VMX
VSX registers.
---
 gdb/NEWS              |   3 +
 gdb/aix-thread.c      | 258 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 222 ++++++++++++++++++++++++++++++++++++
 gdb/rs6000-aix-tdep.c | 182 +++++++++++++++++++++++++++++
 4 files changed, 664 insertions(+), 1 deletion(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 75cd11b204e..e38c5dc64c5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -938,6 +938,9 @@ info sources
 
 ARM Symbian			arm*-*-symbianelf*
 
+GDB no longer supports AIX 4.x, AIX 5.x and AIX 6.x.  The minimum supported
+AIX version is now AIX 7.1.
+
 * New remote packets
 
 qMemTags
diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 4184c87a92b..e465b49738b 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -301,7 +301,16 @@ ptrace_check (int req, int id, int ret)
 			req, id, ret, errno);
 	  return ret == -1 ? 0 : 1;
 	}
-      break;
+	break;
+     case PTT_READ_VEC:
+     case PTT_READ_VSX:
+        if (debug_aix_thread)
+            gdb_printf (gdb_stdlog,
+                        "ptrace (%d, %d) = %d (errno = %d)\n",
+                        req, id, ret, errno);
+	if (ret == -1)
+	  return -1;
+	break;
     }
   error (_("aix-thread: ptrace (%d, %d) returned %d (errno = %d %s)"),
 	 req, id, ret, errno, safe_strerror (errno));
@@ -475,6 +484,42 @@ pdc_read_regs (pthdb_user_t user_current_pid,
 	  memcpy (&context->msr, &sprs32, sizeof(sprs32));
 	}
     }  
+
+  /* vector registers.  */
+  __vmx_context_t vmx;
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+      {
+	if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	  memset (&vmx, 0, sizeof (vmx));
+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+      }
+    else
+      {
+	if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	  memset (&vmx, 0, sizeof (vmx));
+	memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+      }
+  }
+
+  /* vsx registers.  */
+  __vsx_context_t vsx;
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+    {
+	if (!ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	  memset (&vsx, 0, sizeof (vsx));
+	memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+    }
+    else
+    {
+      if (!ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	memset (&vsx, 0, sizeof (vsx));
+      memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+    }
+  }
   return 0;
 }
 
@@ -531,6 +576,24 @@ pdc_write_regs (pthdb_user_t user_current_pid,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &context->msr, 0, NULL);
 	}
     }
+
+  /* vector registers.  */
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+      ptrace64aix (PTT_WRITE_VEC, tid, (unsigned long) &context->vmx, 0, 0);
+    else
+      ptrace32 (PTT_WRITE_VEC, tid, (uintptr_t) &context->vmx, 0, 0);
+  }
+
+  /* vsx registers.  */
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+  {
+    if (data->arch64)
+      ptrace64aix (PTT_WRITE_VSX, tid, (unsigned long) &context->vsx, 0, 0);
+    else
+      ptrace32 (PTT_WRITE_VSX, tid, (uintptr_t) &context->vsx, 0, 0);
+  }
   return 0;
 }
 
@@ -1172,6 +1235,35 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   return pd_update (ptid.pid ());
 }
 
+/* Supply AIX altivec registers, both 64 and 32 bit.  */
+
+static void 
+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+  for (regno = 0; regno < ppc_num_vrs; regno++)
+     regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
+			   &(vmx.__vr[regno]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+}
+
+/* Supply AIX VSX registers, both 64 and 32 bit.  */
+
+static void
+supply_vsx_regs (struct regcache *regcache, __vsx_context_t vsx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+     regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + regno,
+                           &(vsx.__vsr_dw1[regno]));
+}
+
 /* Record that the 64-bit general-purpose registers contain VALS.  */
 
 static void
@@ -1321,6 +1413,12 @@ fetch_regs_user_thread (struct regcache *regcache, pthdb_pthread_t pdtid)
   else
     supply_sprs32 (regcache, ctx.iar, ctx.msr, ctx.cr, ctx.lr, ctx.ctr,
 			     ctx.xer, ctx.fpscr);
+
+  /* Altivec registers.  */
+  supply_altivec_regs (regcache, ctx.vmx);
+
+  /* VSX registers.  */
+  supply_vsx_regs (regcache, ctx.vsx);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from
@@ -1380,6 +1478,38 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	}
     }
 
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      int ret = 0;
+      __vmx_context_t vmx;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
+      if (ret < 0)
+	memset(&vmx, 0, sizeof(__vmx_context_t));
+      for (i = 0; i < ppc_num_vrs; i++)
+	regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      int ret = 0;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      if (ret < 0)
+        memset(&vsx, 0, sizeof(__vsx_context_t));
+      for (i = 0; i < ppc_num_vshrs; i++)
+        regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+    }
+
   /* Floating-point registers.  */
 
   if (ppc_floating_point_unit_p (gdbarch)
@@ -1447,6 +1577,41 @@ aix_thread_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vrs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+				     &(vmx->__vr[regno]));
+
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+    regcache->raw_collect (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum - 1))
+    regcache->raw_collect (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store the gp registers into an array of uint32_t or uint64_t.  */
 
 static void
@@ -1582,6 +1747,9 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
   uint64_t int64;
   struct aix_thread_variables *data;
   data = get_thread_data_helper_for_ptid (inferior_ptid);
+  int ret;
+  __vmx_context_t vmx;
+  __vsx_context_t  vsx;
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1594,6 +1762,44 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
 	   pd_status2str (status));
 
+  /* Fill altivec-registers.  */
+
+  if (__power_vmx())
+  {
+    memset(&vmx, 0, sizeof(__vmx_context_t));
+    if (data->arch64)
+    {
+      for (i = 0; i < ppc_num_vrs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vmx.__vr[i]));
+	    ctx.vmx.__vr[i] = vmx.__vr[i];
+	  }
+      if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+	ctx.vmx.__vrsave = vmx.__vrsave;
+      if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum - 1))
+	ctx.vmx.__vscr = vmx.__vscr;
+    }
+  }
+
+  /* Fill vsx registers. */
+
+  if (__power_vsx())
+  {
+    memset(&vsx, 0, sizeof(__vsx_context_t));
+    if (data->arch64)
+    {
+      for (i = 0; i < ppc_num_vshrs; i++)
+	 if (REG_VALID == regcache->get_register_status (tdep->ppc_vsr0_regnum + i))
+	 {
+	   regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				      &(vsx.__vsr_dw1[i]));
+	   ctx.vsx.__vsr_dw1[i] = vsx.__vsr_dw1[i];
+	 }
+    }
+  }
+
   /* Collect general-purpose register values from the regcache.  */
 
   for (i = 0; i < ppc_num_gprs; i++)
@@ -1674,6 +1880,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
   struct aix_thread_variables *data;
+  int ret = 0;
 
   data = get_thread_data_helper_for_ptid (regcache->ptid ());
 
@@ -1766,6 +1973,55 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+	&& (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+	&& regno <= tdep->ppc_vrsave_regnum)))
+    {
+      __vmx_context_t vmx;
+      if (__power_vmx())
+      {
+	if (data->arch64)
+	  ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+	else
+	  ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+        if (ret > 0)
+        {
+	  fill_altivec(regcache, &vmx);
+	  if (data->arch64)
+	    ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+	  else
+	    ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+	  if (ret < 0)
+	    perror_with_name (_("Unable to store AltiVec register after read"));
+	}
+      }
+    }
+
+    /* VSX registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
+	|| (regno >=tdep->ppc_vsr0_upper_regnum)))
+    {
+      __vsx_context_t vsx;
+      if (__power_vsx())
+      {
+	if (data->arch64)
+	  ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	else
+	  ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	if (ret > 0)
+	{
+	  fill_vsx (regcache, &vsx);
+	  if (data->arch64)
+	    ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+	  else
+	    ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+	  if (ret < 0)
+	    perror_with_name (_("Unable to store VSX register after read"));
+	}
+      }
+    }
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index 8c9dc1a6e68..8cd96778992 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -58,6 +58,14 @@
 #include <procinfo.h>
 #include <sys/types.h>
 
+/* Header files for alti-vec reg.  */
+#include <sys/context.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -99,6 +107,8 @@ class rs6000_nat_target final : public inf_ptrace_target
      support.  */
   void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override;
@@ -272,6 +282,166 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                           &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+    if (ret < 0)
+      return;
+
+    regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+                           regno - tdep->ppc_vsr0_upper_regnum);
+
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+    if (ret < 0)
+      perror_with_name (_("Unable to write VSX registers after reading it"));
+  }
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+      return;
+
+    regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+                                  - tdep->ppc_vr0_regnum);
+
+    if (ARCH64 ())
+      ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+    if (ret < 0)
+      perror_with_name (_("Unable to store AltiVec register after reading it"));
+  }
+
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+    supply_vrregset_aix (regcache, &vmx);
+  }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+  {
+    if (ARCH64 ())
+      rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+    else
+      rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+    supply_vsxregset_aix (regcache, &vsx);
+  }
+}
+
 void rs6000_nat_target::post_startup_inferior (ptid_t ptid)
 {
 
@@ -326,6 +496,20 @@ fetch_register (struct regcache *regcache, int regno)
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
 
+  /* Alti-vec register.  */
+  if (altivec_register_p (gdbarch, regno))
+  {
+    fetch_altivec_registers_aix (regcache);
+    return;
+  }
+
+  /* VSX register.  */
+  if (vsx_register_p (gdbarch, regno))
+  {
+    fetch_vsx_registers_aix (regcache);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -388,6 +572,18 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+  {
+    store_altivec_register_aix (regcache, regno);
+    return;
+  }
+
+  if (vsx_register_p (gdbarch, regno))
+  {
+    store_vsx_register_aix (regcache, regno);
+    return;
+  }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -458,6 +654,12 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
 
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+        fetch_altivec_registers_aix (regcache);
+
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -472,6 +674,26 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+   {
+     if (__power_vsx ())
+       return tdesc_powerpc_vsx64;
+     else if (__power_vmx ())
+       return tdesc_powerpc_altivec64;
+   }
+   else
+   {
+     if (__power_vsx ())
+       return tdesc_powerpc_vsx32;
+     else if (__power_vmx ())
+       return tdesc_powerpc_altivec32;
+   }
+   return NULL;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 15602c80b00..b71bbe750db 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,178 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+                         i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+                                              i++, offset += 16)
+        ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+    ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+        (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+    (const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i, offset = 0;
+
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+                                                   + 32; i++, offset += 8)
+      ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+  {
+    int i;
+    int offset = 0;
+    for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+                                                  + 32; i++, offset += 8)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+    return;
+  }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+  {
+    int i;
+
+    for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+              tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+      ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+    ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+               (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+    ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+             (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+    return;
+  }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +434,20 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data);
+
 }
 
 
-- 
2.38.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-06 13:45                   ` Aditya Kamath1
@ 2023-03-07 10:25                     ` Ulrich Weigand
  2023-03-07 12:13                       ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2023-03-07 10:25 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>So I connected with my seniors on this. So AIX folks are using 7.1 now. 
>So I have changed this to minimum 7.x.. Kindly see it in this patch. 
>For those who are below 7.1, we are not supporting. 

OK, this makes sense to me.  But it looks like you've added this
to the wrong section now, see below.

>>Fix coding style ({ should be indented).
>This is done. I have eliminated all RHS space and aligned the flower brackets wherever I saw it was not aligned.

Unfortunately it seems you changed many of these
in the wrong direction now.  GNU coding style is
to indent the { by two spaces, and then indent the
block inside by *another* two spaces:

  if (condition)
    {
      /* code */
    }

Also, the patch still introduces various instances of
8 spaces (that should be tabs), and whitespace at the
end of the line (which should be removed).


>@@ -938,6 +938,9 @@ info sources
> 
> ARM Symbian			arm*-*-symbianelf*
> 
>+GDB no longer supports AIX 4.x, AIX 5.x and AIX 6.x.  The minimum supported
>+AIX version is now AIX 7.1.
>+

You've added this under the GDB 11 news section, which is wrong.

You should instead add a new section 
  * Removed targets and native configurations
in the topmost 
  *** Changes since GDB 13
section.

>+  __vmx_context_t vmx;
>+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
>+  {

Wrong indentation.

>+  /* vsx registers.  */
>+  __vsx_context_t vsx;
>+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
>+  {

Likewise.

>+  /* vector registers.  */
>+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
>+  {

Likewise.

>+  /* vsx registers.  */
>+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
>+  {

Likewise.

>+  /* Fill altivec-registers.  */
>+
>+  if (__power_vmx())
>+  {

Likewise throughout the block

>+    memset(&vmx, 0, sizeof(__vmx_context_t));
>+    if (data->arch64)

Why is this check necessary, and what happens on 32-bit targets?

>+  /* Fill vsx registers. */
>+
>+  if (__power_vsx())
>+  {
>+    memset(&vsx, 0, sizeof(__vsx_context_t));
>+    if (data->arch64)

Same question, also same indentation issues.

>+    /* Vector registers.  */
>+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
>+	&& (regno == -1 || (regno >= tdep->ppc_vr0_regnum
>+	&& regno <= tdep->ppc_vrsave_regnum)))
>+    {

Also indentation issues throughout the block.

>+    /* VSX registers.  */
>+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
>+	|| (regno >=tdep->ppc_vsr0_upper_regnum)))

You've now removed the upper limit completely.  I think this needs an 
  && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_vshrs

>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx() && thrd_i > 0)
>+  {

Indentation.

>+  memset(&vmx, 0, sizeof(__vmx_context_t));
>+  if (__power_vmx() && thrd_i > 0)
>+  {

Likewise.

>+  memset(&vmx, 0, sizeof(__vmx_context_t));
>+  if (__power_vmx() && thrd_i > 0)
>+  {

Likewise.

>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx() && thrd_i > 0)
>+  {

Likewise.

>+  /* Alti-vec register.  */
>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    fetch_altivec_registers_aix (regcache);
>+    return;
>+  }
>+
>+  /* VSX register.  */
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    fetch_vsx_registers_aix (regcache);
>+    return;
>+  }

Likewise.

>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }

Likewise.

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+   {
>+     if (__power_vsx ())
>+       return tdesc_powerpc_vsx64;
>+     else if (__power_vmx ())
>+       return tdesc_powerpc_altivec64;
>+   }
>+   else
>+   {
>+     if (__power_vsx ())
>+       return tdesc_powerpc_vsx32;
>+     else if (__power_vmx ())
>+       return tdesc_powerpc_altivec32;
>+   }
>+   return NULL;
>+}

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-07 10:25                     ` Ulrich Weigand
@ 2023-03-07 12:13                       ` Aditya Kamath1
  2023-03-07 12:55                         ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2023-03-07 12:13 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 5723 bytes --]

Hi Ulrich and community,

Please find attached the patch with the newly suggested changes with indentations as per GNU style/guidelines.

Thank you for guiding about the same. Kindly see my reply to 2 of your queries in blue.

Kindly push this patch if there are no changes.

Have a nice day ahead.

Thanks and regards,
Aditya.

>You've added this under the GDB 11 news section, which is wrong.

>You should instead add a new section
 > * Removed targets and native configurations
>in the topmost
>  *** Changes since GDB 13
>section.

This is done. Kindly let me know if this is okay.
>+    memset(&vmx, 0, sizeof(__vmx_context_t));
>+    if (data->arch64)

>Why is this check necessary, and what happens on 32-bit targets?

Thank you for reminding me. So I was experimenting with the altivec-regs.exp and site.exp in 32 bit mode attempting to see what happens if I have that condition. I forgot to remove it.

From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Date: Tuesday, 7 March 2023 at 3:55 PM
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>, Aditya Kamath1 <Aditya.Kamath1@ibm.com>, simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX
Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>So I connected with my seniors on this. So AIX folks are using 7.1 now.
>So I have changed this to minimum 7.x.. Kindly see it in this patch.
>For those who are below 7.1, we are not supporting.

OK, this makes sense to me.  But it looks like you've added this
to the wrong section now, see below.

>>Fix coding style ({ should be indented).
>This is done. I have eliminated all RHS space and aligned the flower brackets wherever I saw it was not aligned.

Unfortunately it seems you changed many of these
in the wrong direction now.  GNU coding style is
to indent the { by two spaces, and then indent the
block inside by *another* two spaces:

  if (condition)
    {
      /* code */
    }

Also, the patch still introduces various instances of
8 spaces (that should be tabs), and whitespace at the
end of the line (which should be removed).


>@@ -938,6 +938,9 @@ info sources
>
> ARM Symbian                   arm*-*-symbianelf*
>
>+GDB no longer supports AIX 4.x, AIX 5.x and AIX 6.x.  The minimum supported
>+AIX version is now AIX 7.1.
>+

You've added this under the GDB 11 news section, which is wrong.

You should instead add a new section
  * Removed targets and native configurations
in the topmost
  *** Changes since GDB 13
section.

>+  __vmx_context_t vmx;
>+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
>+  {

Wrong indentation.

>+  /* vsx registers.  */
>+  __vsx_context_t vsx;
>+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
>+  {

Likewise.

>+  /* vector registers.  */
>+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
>+  {

Likewise.

>+  /* vsx registers.  */
>+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
>+  {

Likewise.

>+  /* Fill altivec-registers.  */
>+
>+  if (__power_vmx())
>+  {

Likewise throughout the block

>+    memset(&vmx, 0, sizeof(__vmx_context_t));
>+    if (data->arch64)

Why is this check necessary, and what happens on 32-bit targets?

>+  /* Fill vsx registers. */
>+
>+  if (__power_vsx())
>+  {
>+    memset(&vsx, 0, sizeof(__vsx_context_t));
>+    if (data->arch64)

Same question, also same indentation issues.

>+    /* Vector registers.  */
>+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
>+      && (regno == -1 || (regno >= tdep->ppc_vr0_regnum
>+      && regno <= tdep->ppc_vrsave_regnum)))
>+    {

Also indentation issues throughout the block.

>+    /* VSX registers.  */
>+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
>+      || (regno >=tdep->ppc_vsr0_upper_regnum)))

You've now removed the upper limit completely.  I think this needs an
  && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_vshrs

>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx() && thrd_i > 0)
>+  {

Indentation.

>+  memset(&vmx, 0, sizeof(__vmx_context_t));
>+  if (__power_vmx() && thrd_i > 0)
>+  {

Likewise.

>+  memset(&vmx, 0, sizeof(__vmx_context_t));
>+  if (__power_vmx() && thrd_i > 0)
>+  {

Likewise.

>+  memset(&vsx, 0, sizeof(__vsx_context_t));
>+  if (__power_vsx() && thrd_i > 0)
>+  {

Likewise.

>+  /* Alti-vec register.  */
>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    fetch_altivec_registers_aix (regcache);
>+    return;
>+  }
>+
>+  /* VSX register.  */
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    fetch_vsx_registers_aix (regcache);
>+    return;
>+  }

Likewise.

>+  if (altivec_register_p (gdbarch, regno))
>+  {
>+    store_altivec_register_aix (regcache, regno);
>+    return;
>+  }
>+
>+  if (vsx_register_p (gdbarch, regno))
>+  {
>+    store_vsx_register_aix (regcache, regno);
>+    return;
>+  }

Likewise.

>+const struct target_desc *
>+rs6000_nat_target::read_description ()
>+{
>+   if (ARCH64())
>+   {
>+     if (__power_vsx ())
>+       return tdesc_powerpc_vsx64;
>+     else if (__power_vmx ())
>+       return tdesc_powerpc_altivec64;
>+   }
>+   else
>+   {
>+     if (__power_vsx ())
>+       return tdesc_powerpc_vsx32;
>+     else if (__power_vmx ())
>+       return tdesc_powerpc_altivec32;
>+   }
>+   return NULL;
>+}

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

>+  if (regnum == -1)
>+  {

Likewise.

Bye,
Ulrich

[-- Attachment #2: 0001-Enable-vector-instruction-debugging-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26138 bytes --]

From 5fcb5e2f50416ef63e51bcc022e8db00ec59bf5e Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Tue, 7 Mar 2023 05:57:56 -0600
Subject: [PATCH] Enable vector instruction debugging for AIX

AIX now supports vector register contents debugging for both VMX
VSX registers.
---
 gdb/NEWS              |   5 +
 gdb/aix-thread.c      | 252 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 221 ++++++++++++++++++++++++++++++++++++
 gdb/rs6000-aix-tdep.c | 182 ++++++++++++++++++++++++++++++
 4 files changed, 659 insertions(+), 1 deletion(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 75cd11b204e..f456f52523b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,11 @@
 
 *** Changes since GDB 13
 
+* Removed targets and native configurations
+
+  GDB no longer supports AIX 4.x, AIX 5.x and AIX 6.x.  The minimum supported
+  AIX version is now AIX 7.1.
+
 * Multi-target feature configuration
 
   GDB now supports the individual configuration of remote targets' feature
diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 4184c87a92b..650cfcb639b 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -301,7 +301,16 @@ ptrace_check (int req, int id, int ret)
 			req, id, ret, errno);
 	  return ret == -1 ? 0 : 1;
 	}
-      break;
+	break;
+     case PTT_READ_VEC:
+     case PTT_READ_VSX:
+        if (debug_aix_thread)
+            gdb_printf (gdb_stdlog,
+                        "ptrace (%d, %d) = %d (errno = %d)\n",
+                        req, id, ret, errno);
+	if (ret == -1)
+	  return -1;
+	break;
     }
   error (_("aix-thread: ptrace (%d, %d) returned %d (errno = %d %s)"),
 	 req, id, ret, errno, safe_strerror (errno));
@@ -475,6 +484,42 @@ pdc_read_regs (pthdb_user_t user_current_pid,
 	  memcpy (&context->msr, &sprs32, sizeof(sprs32));
 	}
     }  
+
+  /* vector registers.  */
+  __vmx_context_t vmx;
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	{
+	  if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	    memset (&vmx, 0, sizeof (vmx));
+	  memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+	}
+      else
+	{
+	  if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	    memset (&vmx, 0, sizeof (vmx));
+	   memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+	}
+    }
+
+  /* vsx registers.  */
+  __vsx_context_t vsx;
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	{
+	  if (!ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	    memset (&vsx, 0, sizeof (vsx));
+	  memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+	}
+      else
+	{
+	  if (!ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	    memset (&vsx, 0, sizeof (vsx));
+	  memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+	}
+    }
   return 0;
 }
 
@@ -531,6 +576,24 @@ pdc_write_regs (pthdb_user_t user_current_pid,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &context->msr, 0, NULL);
 	}
     }
+
+  /* vector registers.  */
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	ptrace64aix (PTT_WRITE_VEC, tid, (unsigned long) &context->vmx, 0, 0);
+      else
+	ptrace32 (PTT_WRITE_VEC, tid, (uintptr_t) &context->vmx, 0, 0);
+    }
+
+  /* vsx registers.  */
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	ptrace64aix (PTT_WRITE_VSX, tid, (unsigned long) &context->vsx, 0, 0);
+      else
+	ptrace32 (PTT_WRITE_VSX, tid, (uintptr_t) &context->vsx, 0, 0);
+    }
   return 0;
 }
 
@@ -1172,6 +1235,35 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   return pd_update (ptid.pid ());
 }
 
+/* Supply AIX altivec registers, both 64 and 32 bit.  */
+
+static void 
+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+  for (regno = 0; regno < ppc_num_vrs; regno++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
+			  &(vmx.__vr[regno]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+}
+
+/* Supply AIX VSX registers, both 64 and 32 bit.  */
+
+static void
+supply_vsx_regs (struct regcache *regcache, __vsx_context_t vsx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + regno,
+			  &(vsx.__vsr_dw1[regno]));
+}
+
 /* Record that the 64-bit general-purpose registers contain VALS.  */
 
 static void
@@ -1321,6 +1413,12 @@ fetch_regs_user_thread (struct regcache *regcache, pthdb_pthread_t pdtid)
   else
     supply_sprs32 (regcache, ctx.iar, ctx.msr, ctx.cr, ctx.lr, ctx.ctr,
 			     ctx.xer, ctx.fpscr);
+
+  /* Altivec registers.  */
+  supply_altivec_regs (regcache, ctx.vmx);
+
+  /* VSX registers.  */
+  supply_vsx_regs (regcache, ctx.vsx);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from
@@ -1380,6 +1478,38 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	}
     }
 
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      int ret = 0;
+      __vmx_context_t vmx;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
+      if (ret < 0)
+	memset(&vmx, 0, sizeof(__vmx_context_t));
+      for (i = 0; i < ppc_num_vrs; i++)
+	regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      int ret = 0;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      if (ret < 0)
+        memset(&vsx, 0, sizeof(__vsx_context_t));
+      for (i = 0; i < ppc_num_vshrs; i++)
+        regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+    }
+
   /* Floating-point registers.  */
 
   if (ppc_floating_point_unit_p (gdbarch)
@@ -1447,6 +1577,41 @@ aix_thread_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vrs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+				     &(vmx->__vr[regno]));
+
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+    regcache->raw_collect (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum - 1))
+    regcache->raw_collect (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store the gp registers into an array of uint32_t or uint64_t.  */
 
 static void
@@ -1582,6 +1747,9 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
   uint64_t int64;
   struct aix_thread_variables *data;
   data = get_thread_data_helper_for_ptid (inferior_ptid);
+  int ret;
+  __vmx_context_t vmx;
+  __vsx_context_t  vsx;
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1594,6 +1762,38 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
 	   pd_status2str (status));
 
+  /* Fill altivec-registers.  */
+
+  if (__power_vmx())
+    {
+      memset(&vmx, 0, sizeof(__vmx_context_t));
+      for (i = 0; i < ppc_num_vrs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vmx.__vr[i]));
+	    ctx.vmx.__vr[i] = vmx.__vr[i];
+	  }
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+	  ctx.vmx.__vrsave = vmx.__vrsave;
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum - 1))
+	  ctx.vmx.__vscr = vmx.__vscr;
+    }
+
+  /* Fill vsx registers. */
+
+  if (__power_vsx())
+    {
+      memset(&vsx, 0, sizeof(__vsx_context_t));
+      for (i = 0; i < ppc_num_vshrs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vsr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vsx.__vsr_dw1[i]));
+	    ctx.vsx.__vsr_dw1[i] = vsx.__vsr_dw1[i];
+	  }
+    }
+
   /* Collect general-purpose register values from the regcache.  */
 
   for (i = 0; i < ppc_num_gprs; i++)
@@ -1674,6 +1874,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
   struct aix_thread_variables *data;
+  int ret = 0;
 
   data = get_thread_data_helper_for_ptid (regcache->ptid ());
 
@@ -1766,6 +1967,55 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+	&& (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+	&& regno <= tdep->ppc_vrsave_regnum)))
+      {
+	__vmx_context_t vmx;
+	if (__power_vmx())
+	  {
+	    if (data->arch64)
+	      ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+	    else
+	      ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+	    if (ret > 0)
+	      {
+		fill_altivec(regcache, &vmx);
+		if (data->arch64)
+		  ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+		else
+		  ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+		if (ret < 0)
+		  perror_with_name (_("Unable to store AltiVec register after read"));
+	      }
+	  }
+      }
+
+    /* VSX registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
+	|| (regno >=tdep->ppc_vsr0_upper_regnum)))
+      {
+	__vsx_context_t vsx;
+	if (__power_vsx())
+	  {
+	    if (data->arch64)
+	      ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	    else
+	      ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	    if (ret > 0)
+	      {
+		fill_vsx (regcache, &vsx);
+		if (data->arch64)
+		  ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+		else
+		  ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+		if (ret < 0)
+		  perror_with_name (_("Unable to store VSX register after read"));
+	      }
+	  }
+      }
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index 8c9dc1a6e68..728b23bc86e 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -58,6 +58,14 @@
 #include <procinfo.h>
 #include <sys/types.h>
 
+/* Header files for alti-vec reg.  */
+#include <sys/context.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -99,6 +107,8 @@ class rs6000_nat_target final : public inf_ptrace_target
      support.  */
   void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override;
@@ -272,6 +282,165 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                           &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+      if (ret < 0)
+	return;
+
+      regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+			     regno - tdep->ppc_vsr0_upper_regnum);
+
+      if (ARCH64 ())
+	 ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+      else
+	 ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+      if (ret < 0)
+	perror_with_name (_("Unable to write VSX registers after reading it"));
+    }
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+      if (ret < 0)
+	return;
+
+      regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+			     - tdep->ppc_vr0_regnum);
+
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+      if (ret < 0)
+	perror_with_name (_("Unable to store AltiVec register after reading it"));
+    }
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+      else
+	rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+      supply_vrregset_aix (regcache, &vmx);
+    }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+      else
+	rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+      supply_vsxregset_aix (regcache, &vsx);
+    }
+}
+
 void rs6000_nat_target::post_startup_inferior (ptid_t ptid)
 {
 
@@ -326,6 +495,20 @@ fetch_register (struct regcache *regcache, int regno)
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
 
+  /* Alti-vec register.  */
+  if (altivec_register_p (gdbarch, regno))
+    {
+      fetch_altivec_registers_aix (regcache);
+      return;
+    }
+
+  /* VSX register.  */
+  if (vsx_register_p (gdbarch, regno))
+    {
+      fetch_vsx_registers_aix (regcache);
+      return;
+    }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -388,6 +571,18 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+    {
+      store_altivec_register_aix (regcache, regno);
+      return;
+    }
+
+  if (vsx_register_p (gdbarch, regno))
+    {
+      store_vsx_register_aix (regcache, regno);
+      return;
+    }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -458,6 +653,12 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
 
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+        fetch_altivec_registers_aix (regcache);
+
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -472,6 +673,26 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+     {
+       if (__power_vsx ())
+	 return tdesc_powerpc_vsx64;
+       else if (__power_vmx ())
+	 return tdesc_powerpc_altivec64;
+     }
+   else
+     {
+       if (__power_vsx ())
+	 return tdesc_powerpc_vsx32;
+       else if (__power_vmx ())
+	 return tdesc_powerpc_altivec32;
+     }
+   return NULL;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 15602c80b00..9a3a5396508 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,178 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+    {
+      int i;
+
+      for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+			   i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+						i++, offset += 16)
+	ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+      ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+	  (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+      ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+	(const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+      return;
+    }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+    {
+      int i, offset = 0;
+
+      for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+						     + 32; i++, offset += 8)
+	ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+      return;
+    }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+    {
+      int i;
+      int offset = 0;
+      for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+						     + 32; i++, offset += 8)
+	ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+      return;
+    }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+    {
+      int i;
+
+      for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+		tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+	ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+      ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+		 (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+      ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+	 (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+      return;
+    }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +434,20 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data);
+
 }
 
 
-- 
2.38.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-07 12:13                       ` Aditya Kamath1
@ 2023-03-07 12:55                         ` Ulrich Weigand
  2023-03-07 13:24                           ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2023-03-07 12:55 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Kindly push this patch if there are no changes. 

This one issue still isn't addressed:

>>+    /* VSX registers.  */
>>+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
>>+      || (regno >=tdep->ppc_vsr0_upper_regnum)))
>
>You've now removed the upper limit completely.  I think this needs an 
>  && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_vshrs

Otherwise, everything looks good to me now.

Bye,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-07 12:55                         ` Ulrich Weigand
@ 2023-03-07 13:24                           ` Aditya Kamath1
  2023-03-07 15:53                             ` Ulrich Weigand
  0 siblings, 1 reply; 18+ messages in thread
From: Aditya Kamath1 @ 2023-03-07 13:24 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 1371 bytes --]

Hi Ulrich and community,

Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

Please see my reply to your comments marked in blue.

Kindly push this patch if there are no further changes.

Have a nice day ahead.

Thanks and regards,
Aditya.

>+    /* VSX registers.  */
>+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
>+       || (regno >=tdep->ppc_vsr0_upper_regnum
>+       && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_vshrs)))

Here it is in this patch.

From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Date: Tuesday, 7 March 2023 at 6:25 PM
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>, Aditya Kamath1 <Aditya.Kamath1@ibm.com>, simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX
Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Kindly push this patch if there are no changes.

This one issue still isn't addressed:

>>+    /* VSX registers.  */
>>+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
>>+      || (regno >=tdep->ppc_vsr0_upper_regnum)))
>
>You've now removed the upper limit completely.  I think this needs an
>  && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_vshrs

Otherwise, everything looks good to me now.

Bye,
Ulrich

[-- Attachment #2: 0001-Enable-vector-instruction-debugging-for-AIX.patch --]
[-- Type: application/octet-stream, Size: 26193 bytes --]

From 890b9e090980977d2db054b3f4cde3e2eedaad29 Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Tue, 7 Mar 2023 07:22:19 -0600
Subject: [PATCH] Enable vector instruction debugging for AIX

AIX now supports vector register contents debugging for both VMX
VSX registers.
---
 gdb/NEWS              |   5 +
 gdb/aix-thread.c      | 253 +++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-aix-nat.c  | 221 ++++++++++++++++++++++++++++++++++++
 gdb/rs6000-aix-tdep.c | 182 ++++++++++++++++++++++++++++++
 4 files changed, 660 insertions(+), 1 deletion(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 75cd11b204e..f456f52523b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,11 @@
 
 *** Changes since GDB 13
 
+* Removed targets and native configurations
+
+  GDB no longer supports AIX 4.x, AIX 5.x and AIX 6.x.  The minimum supported
+  AIX version is now AIX 7.1.
+
 * Multi-target feature configuration
 
   GDB now supports the individual configuration of remote targets' feature
diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 4184c87a92b..e8f57fe185a 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -301,7 +301,16 @@ ptrace_check (int req, int id, int ret)
 			req, id, ret, errno);
 	  return ret == -1 ? 0 : 1;
 	}
-      break;
+	break;
+     case PTT_READ_VEC:
+     case PTT_READ_VSX:
+        if (debug_aix_thread)
+            gdb_printf (gdb_stdlog,
+                        "ptrace (%d, %d) = %d (errno = %d)\n",
+                        req, id, ret, errno);
+	if (ret == -1)
+	  return -1;
+	break;
     }
   error (_("aix-thread: ptrace (%d, %d) returned %d (errno = %d %s)"),
 	 req, id, ret, errno, safe_strerror (errno));
@@ -475,6 +484,42 @@ pdc_read_regs (pthdb_user_t user_current_pid,
 	  memcpy (&context->msr, &sprs32, sizeof(sprs32));
 	}
     }  
+
+  /* vector registers.  */
+  __vmx_context_t vmx;
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	{
+	  if (!ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	    memset (&vmx, 0, sizeof (vmx));
+	  memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+	}
+      else
+	{
+	  if (!ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0))
+	    memset (&vmx, 0, sizeof (vmx));
+	   memcpy (&context->vmx, &vmx, sizeof(__vmx_context_t));
+	}
+    }
+
+  /* vsx registers.  */
+  __vsx_context_t vsx;
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	{
+	  if (!ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	    memset (&vsx, 0, sizeof (vsx));
+	  memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+	}
+      else
+	{
+	  if (!ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0))
+	    memset (&vsx, 0, sizeof (vsx));
+	  memcpy (&context->vsx, &vsx, sizeof(__vsx_context_t));
+	}
+    }
   return 0;
 }
 
@@ -531,6 +576,24 @@ pdc_write_regs (pthdb_user_t user_current_pid,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &context->msr, 0, NULL);
 	}
     }
+
+  /* vector registers.  */
+  if (__power_vmx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	ptrace64aix (PTT_WRITE_VEC, tid, (unsigned long) &context->vmx, 0, 0);
+      else
+	ptrace32 (PTT_WRITE_VEC, tid, (uintptr_t) &context->vmx, 0, 0);
+    }
+
+  /* vsx registers.  */
+  if (__power_vsx() && (flags & PTHDB_FLAG_REGS))
+    {
+      if (data->arch64)
+	ptrace64aix (PTT_WRITE_VSX, tid, (unsigned long) &context->vsx, 0, 0);
+      else
+	ptrace32 (PTT_WRITE_VSX, tid, (uintptr_t) &context->vsx, 0, 0);
+    }
   return 0;
 }
 
@@ -1172,6 +1235,35 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   return pd_update (ptid.pid ());
 }
 
+/* Supply AIX altivec registers, both 64 and 32 bit.  */
+
+static void 
+supply_altivec_regs (struct regcache *regcache, __vmx_context_t vmx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+  for (regno = 0; regno < ppc_num_vrs; regno++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + regno,
+			  &(vmx.__vr[regno]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+}
+
+/* Supply AIX VSX registers, both 64 and 32 bit.  */
+
+static void
+supply_vsx_regs (struct regcache *regcache, __vsx_context_t vsx)
+{
+  ppc_gdbarch_tdep *tdep
+    = gdbarch_tdep<ppc_gdbarch_tdep> (regcache->arch ());
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + regno,
+			  &(vsx.__vsr_dw1[regno]));
+}
+
 /* Record that the 64-bit general-purpose registers contain VALS.  */
 
 static void
@@ -1321,6 +1413,12 @@ fetch_regs_user_thread (struct regcache *regcache, pthdb_pthread_t pdtid)
   else
     supply_sprs32 (regcache, ctx.iar, ctx.msr, ctx.cr, ctx.lr, ctx.ctr,
 			     ctx.xer, ctx.fpscr);
+
+  /* Altivec registers.  */
+  supply_altivec_regs (regcache, ctx.vmx);
+
+  /* VSX registers.  */
+  supply_vsx_regs (regcache, ctx.vsx);
 }
 
 /* Fetch register REGNO if != -1 or all registers otherwise from
@@ -1380,6 +1478,38 @@ fetch_regs_kernel_thread (struct regcache *regcache, int regno,
 	}
     }
 
+  /* vector registers.  */
+  if (tdep->ppc_vr0_regnum != -1)
+    {
+      int ret = 0;
+      __vmx_context_t vmx;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VEC, tid, (uintptr_t) &vmx, 0, 0);
+      if (ret < 0)
+	memset(&vmx, 0, sizeof(__vmx_context_t));
+      for (i = 0; i < ppc_num_vrs; i++)
+	regcache->raw_supply (tdep->ppc_vr0_regnum + i, &(vmx.__vr[i]));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx.__vrsave));
+      regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx.__vscr));
+    }
+
+  /* vsx registers.  */
+  if (tdep->ppc_vsr0_upper_regnum != -1)
+    {
+      __vsx_context_t vsx;
+      int ret = 0;
+      if (data->arch64)
+	ret = ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      else
+	ret = ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+      if (ret < 0)
+        memset(&vsx, 0, sizeof(__vsx_context_t));
+      for (i = 0; i < ppc_num_vshrs; i++)
+        regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i, &(vsx.__vsr_dw1[i]));
+    }
+
   /* Floating-point registers.  */
 
   if (ppc_floating_point_unit_p (gdbarch)
@@ -1447,6 +1577,41 @@ aix_thread_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+/* Fill altivec registers.  */
+
+static void
+fill_altivec (const struct regcache *regcache, __vmx_context_t *vmx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vrs; regno++)
+    if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vr0_regnum + regno,
+				     &(vmx->__vr[regno]));
+
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+    regcache->raw_collect (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum - 1))
+    regcache->raw_collect (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fill vsx registers. */
+
+static void
+fill_vsx (const struct regcache *regcache, __vsx_context_t  *vsx)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int regno;
+
+  for (regno = 0; regno < ppc_num_vshrs; regno++)
+    if (REG_VALID == regcache->get_register_status ( tdep->ppc_vsr0_upper_regnum + regno))
+      regcache->raw_collect (tdep->ppc_vsr0_upper_regnum + regno,
+                                   &(vsx->__vsr_dw1[0]) + regno);
+}
+
 /* Store the gp registers into an array of uint32_t or uint64_t.  */
 
 static void
@@ -1582,6 +1747,9 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
   uint64_t int64;
   struct aix_thread_variables *data;
   data = get_thread_data_helper_for_ptid (inferior_ptid);
+  int ret;
+  __vmx_context_t vmx;
+  __vsx_context_t  vsx;
 
   if (debug_aix_thread)
     gdb_printf (gdb_stdlog, 
@@ -1594,6 +1762,38 @@ store_regs_user_thread (const struct regcache *regcache, pthdb_pthread_t pdtid)
     error (_("aix-thread: store_registers: pthdb_pthread_context returned %s"),
 	   pd_status2str (status));
 
+  /* Fill altivec-registers.  */
+
+  if (__power_vmx())
+    {
+      memset(&vmx, 0, sizeof(__vmx_context_t));
+      for (i = 0; i < ppc_num_vrs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vmx.__vr[i]));
+	    ctx.vmx.__vr[i] = vmx.__vr[i];
+	  }
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum))
+	  ctx.vmx.__vrsave = vmx.__vrsave;
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vrsave_regnum - 1))
+	  ctx.vmx.__vscr = vmx.__vscr;
+    }
+
+  /* Fill vsx registers. */
+
+  if (__power_vsx())
+    {
+      memset(&vsx, 0, sizeof(__vsx_context_t));
+      for (i = 0; i < ppc_num_vshrs; i++)
+	if (REG_VALID == regcache->get_register_status (tdep->ppc_vsr0_regnum + i))
+	  {
+	    regcache->raw_collect (tdep->ppc_vr0_regnum + i,
+				   &(vsx.__vsr_dw1[i]));
+	    ctx.vsx.__vsr_dw1[i] = vsx.__vsr_dw1[i];
+	  }
+    }
+
   /* Collect general-purpose register values from the regcache.  */
 
   for (i = 0; i < ppc_num_gprs; i++)
@@ -1674,6 +1874,7 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
   struct ptxsprs sprs64;
   struct ptsprs  sprs32;
   struct aix_thread_variables *data;
+  int ret = 0;
 
   data = get_thread_data_helper_for_ptid (regcache->ptid ());
 
@@ -1766,6 +1967,56 @@ store_regs_kernel_thread (const struct regcache *regcache, int regno,
 	  ptrace32 (PTT_WRITE_SPRS, tid, (uintptr_t) &sprs32, 0, NULL);
 	}
     }
+    
+    /* Vector registers.  */
+    if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1
+	&& (regno == -1 || (regno >= tdep->ppc_vr0_regnum
+	&& regno <= tdep->ppc_vrsave_regnum)))
+      {
+	__vmx_context_t vmx;
+	if (__power_vmx())
+	  {
+	    if (data->arch64)
+	      ret = ptrace64aix (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+	    else
+	      ret = ptrace32 (PTT_READ_VEC, tid, (long long) &vmx, 0, 0);
+	    if (ret > 0)
+	      {
+		fill_altivec(regcache, &vmx);
+		if (data->arch64)
+		  ret = ptrace64aix (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+		else
+		  ret = ptrace32 (PTT_WRITE_VEC, tid, (long long) &vmx, 0, 0);
+		if (ret < 0)
+		  perror_with_name (_("Unable to store AltiVec register after read"));
+	      }
+	  }
+      }
+
+    /* VSX registers.  */
+    if (tdep->ppc_vsr0_upper_regnum != -1 && (regno == -1
+	|| (regno >=tdep->ppc_vsr0_upper_regnum
+	&& regno < tdep->ppc_vsr0_upper_regnum + ppc_num_vshrs)))
+      {
+	__vsx_context_t vsx;
+	if (__power_vsx())
+	  {
+	    if (data->arch64)
+	      ret =  ptrace64aix (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	    else
+	      ret =  ptrace32 (PTT_READ_VSX, tid, (long long) &vsx, 0, 0);
+	    if (ret > 0)
+	      {
+		fill_vsx (regcache, &vsx);
+		if (data->arch64)
+		  ret = ptrace64aix (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+		else
+		  ret = ptrace32 (PTT_WRITE_VSX, tid, (long long) &vsx, 0, 0);
+		if (ret < 0)
+		  perror_with_name (_("Unable to store VSX register after read"));
+	      }
+	  }
+      }
 }
 
 /* Store gdb's current view of the register set into the
diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c
index 8c9dc1a6e68..728b23bc86e 100644
--- a/gdb/rs6000-aix-nat.c
+++ b/gdb/rs6000-aix-nat.c
@@ -58,6 +58,14 @@
 #include <procinfo.h>
 #include <sys/types.h>
 
+/* Header files for alti-vec reg.  */
+#include <sys/context.h>
+
+#include "features/rs6000/powerpc-vsx64.c"
+#include "features/rs6000/powerpc-vsx32.c"
+#include "features/rs6000/powerpc-altivec32.c"
+#include "features/rs6000/powerpc-altivec64.c"
+
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
    accessing fields in the appropriate structures.  */
@@ -99,6 +107,8 @@ class rs6000_nat_target final : public inf_ptrace_target
      support.  */
   void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override;
 
+  const struct target_desc *read_description ()  override;
+
 protected:
 
   void post_startup_inferior (ptid_t ptid) override;
@@ -272,6 +282,165 @@ rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
   return ret;
 }
 
+/* Store the vsx registers.  */
+
+static void
+store_vsx_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                           &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *)&vsx, 0, 0);
+      if (ret < 0)
+	return;
+
+      regcache->raw_collect (regno, &(vsx.__vsr_dw1[0])+
+			     regno - tdep->ppc_vsr0_upper_regnum);
+
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_WRITE_VSX, thrd_i, (long long) &vsx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_WRITE_VSX, thrd_i, (int *) &vsx, 0, 0);
+
+      if (ret < 0)
+	perror_with_name (_("Unable to write VSX registers after reading it"));
+    }
+}
+
+/* Store Altivec registers.  */
+
+static void
+store_altivec_register_aix (struct regcache *regcache, int regno)
+{
+  int ret;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = inferior_ptid.pid ();
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+      if (ret < 0)
+	return;
+
+      regcache->raw_collect (regno, &(vmx.__vr[0]) + regno
+			     - tdep->ppc_vr0_regnum);
+
+      if (ARCH64 ())
+	ret = rs6000_ptrace64 (PTT_WRITE_VEC, thrd_i, (long long) &vmx, 0, 0);
+      else
+	ret = rs6000_ptrace32 (PTT_WRITE_VEC, thrd_i, (int *) &vmx, 0, 0);
+      if (ret < 0)
+	perror_with_name (_("Unable to store AltiVec register after reading it"));
+    }
+}
+
+/* Supply altivec registers.  */
+
+static void
+supply_vrregset_aix (struct regcache *regcache, __vmx_context_t *vmx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+
+  for (i = 0; i < num_of_vrregs; i++)
+    regcache->raw_supply (tdep->ppc_vr0_regnum + i,
+                                    &(vmx->__vr[i]));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum, &(vmx->__vrsave));
+  regcache->raw_supply (tdep->ppc_vrsave_regnum - 1, &(vmx->__vscr));
+}
+
+/* Fetch altivec register.  */
+
+static void
+fetch_altivec_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vmx_context_t vmx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                               &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vmx, 0, sizeof(__vmx_context_t));
+  if (__power_vmx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	rs6000_ptrace64 (PTT_READ_VEC, thrd_i, (long long) &vmx, 0, 0);
+      else
+	rs6000_ptrace32 (PTT_READ_VEC, thrd_i, (int *) &vmx, 0, 0);
+      supply_vrregset_aix (regcache, &vmx);
+    }
+}
+
+/* supply vsx register.  */
+
+static void
+supply_vsxregset_aix (struct regcache *regcache, __vsx_context_t *vsx)
+{
+  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+
+  for (i = 0; i < ppc_num_vshrs; i++)
+   regcache->raw_supply (tdep->ppc_vsr0_upper_regnum + i,
+                                   &(vsx->__vsr_dw1[i]));
+}
+
+/* Fetch vsx registers.  */
+static void
+fetch_vsx_registers_aix (struct regcache *regcache)
+{
+  struct thrdentry64 thrdentry;
+  __vsx_context_t vsx;
+  pid_t pid = current_inferior ()->pid;
+  tid64_t  thrd_i = 0;
+
+  if (getthrds64(pid, &thrdentry, sizeof(struct thrdentry64),
+                                            &thrd_i, 1) == 1)
+    thrd_i = thrdentry.ti_tid;
+
+  memset(&vsx, 0, sizeof(__vsx_context_t));
+  if (__power_vsx() && thrd_i > 0)
+    {
+      if (ARCH64 ())
+	rs6000_ptrace64 (PTT_READ_VSX, thrd_i, (long long) &vsx, 0, 0);
+      else
+	rs6000_ptrace32 (PTT_READ_VSX, thrd_i, (int *) &vsx, 0, 0);
+      supply_vsxregset_aix (regcache, &vsx);
+    }
+}
+
 void rs6000_nat_target::post_startup_inferior (ptid_t ptid)
 {
 
@@ -326,6 +495,20 @@ fetch_register (struct regcache *regcache, int regno)
   /* Retrieved values may be -1, so infer errors from errno.  */
   errno = 0;
 
+  /* Alti-vec register.  */
+  if (altivec_register_p (gdbarch, regno))
+    {
+      fetch_altivec_registers_aix (regcache);
+      return;
+    }
+
+  /* VSX register.  */
+  if (vsx_register_p (gdbarch, regno))
+    {
+      fetch_vsx_registers_aix (regcache);
+      return;
+    }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -388,6 +571,18 @@ store_register (struct regcache *regcache, int regno)
   /* -1 can be a successful return value, so infer errors from errno.  */
   errno = 0;
 
+  if (altivec_register_p (gdbarch, regno))
+    {
+      store_altivec_register_aix (regcache, regno);
+      return;
+    }
+
+  if (vsx_register_p (gdbarch, regno))
+    {
+      store_vsx_register_aix (regcache, regno);
+      return;
+    }
+
   nr = regmap (gdbarch, regno, &isfloat);
 
   /* Floating-point registers.  */
@@ -458,6 +653,12 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
 	for (regno = 0; regno < ppc_num_fprs; regno++)
 	  fetch_register (regcache, tdep->ppc_fp0_regnum + regno);
 
+      if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+        fetch_altivec_registers_aix (regcache);
+
+      if (tdep->ppc_vsr0_upper_regnum != -1)
+        fetch_vsx_registers_aix (regcache);
+
       /* Read special registers.  */
       fetch_register (regcache, gdbarch_pc_regnum (gdbarch));
       fetch_register (regcache, tdep->ppc_ps_regnum);
@@ -472,6 +673,26 @@ rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
     }
 }
 
+const struct target_desc *
+rs6000_nat_target::read_description ()
+{
+   if (ARCH64())
+     {
+       if (__power_vsx ())
+	 return tdesc_powerpc_vsx64;
+       else if (__power_vmx ())
+	 return tdesc_powerpc_altivec64;
+     }
+   else
+     {
+       if (__power_vsx ())
+	 return tdesc_powerpc_vsx32;
+       else if (__power_vmx ())
+	 return tdesc_powerpc_altivec32;
+     }
+   return NULL;
+}
+
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 15602c80b00..9a3a5396508 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -68,6 +68,178 @@
 /* Minimum possible text address in AIX.  */
 #define AIX_TEXT_SEGMENT_BASE 0x10000000
 
+struct rs6000_aix_reg_vrreg_offset
+{
+  int vr0_offset;
+  int vscr_offset;
+  int vrsave_offset;
+};
+
+static struct rs6000_aix_reg_vrreg_offset rs6000_aix_vrreg_offset =
+{
+   /* AltiVec registers.  */
+  32, /* vr0_offset */
+  544, /* vscr_offset. */
+  560 /* vrsave_offset */
+};
+
+static int
+rs6000_aix_get_vrreg_offset (ppc_gdbarch_tdep *tdep,
+  const struct rs6000_aix_reg_vrreg_offset *offsets,
+                                         int regnum)
+{
+  if (regnum >= tdep->ppc_vr0_regnum &&
+  regnum < tdep->ppc_vr0_regnum + ppc_num_vrs)
+    return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16;
+
+  if (regnum == tdep->ppc_vrsave_regnum - 1)
+    return offsets->vscr_offset;
+
+  if (regnum == tdep->ppc_vrsave_regnum)
+    return offsets->vrsave_offset;
+
+  return -1;
+}
+
+static void
+rs6000_aix_supply_vrregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset  *offsets;
+  size_t offset;
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0  && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+    {
+      int i;
+
+      for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset;
+			   i < tdep->ppc_vr0_regnum + ppc_num_vrs;
+						i++, offset += 16)
+	ppc_supply_reg (regcache, i, (const gdb_byte *) vrregs, offset, 16);
+
+      ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+	  (const gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+      ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum,
+	(const gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+      return;
+    }
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum &&
+      regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_supply_reg (regcache, regnum,
+     (const gdb_byte *) vrregs, offset, 4);
+
+}
+
+static void
+rs6000_aix_supply_vsxregset (const struct regset *regset, struct regcache *regcache,
+                                        int regnum, const void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+    {
+      int i, offset = 0;
+
+      for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum 
+						     + 32; i++, offset += 8)
+	ppc_supply_reg (regcache, i, (const gdb_byte *) vsxregs, offset, 8);
+
+      return;
+    }
+  else
+    ppc_supply_reg (regcache, regnum, (const gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vsxregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                    int regnum, void *vsxregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vsr0_regnum >= 0))
+    return;
+
+  if (regnum == -1)
+    {
+      int i;
+      int offset = 0;
+      for (i = tdep->ppc_vsr0_upper_regnum; i < tdep->ppc_vsr0_upper_regnum
+						     + 32; i++, offset += 8)
+	ppc_collect_reg (regcache, i, (gdb_byte *) vsxregs, offset, 8);
+
+      return;
+    }
+
+ else
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vsxregs, 0, 8);
+}
+
+static void
+rs6000_aix_collect_vrregset (const struct regset *regset,
+                         const struct regcache *regcache,
+                    int regnum, void *vrregs, size_t len)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  const struct rs6000_aix_reg_vrreg_offset *offsets;
+  size_t offset;
+
+  ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  if (!(tdep->ppc_vr0_regnum >= 0 && tdep->ppc_vrsave_regnum >= 0))
+    return;
+
+  offsets = (const struct rs6000_aix_reg_vrreg_offset *) regset->regmap;
+  if (regnum == -1)
+    {
+      int i;
+
+      for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; i <
+		tdep->ppc_vr0_regnum + ppc_num_vrs; i++, offset += 16)
+	ppc_collect_reg (regcache, i, (gdb_byte *) vrregs, offset, 16);
+
+      ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1),
+		 (gdb_byte *) vrregs, offsets->vscr_offset, 4);
+
+      ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum,
+	 (gdb_byte *) vrregs, offsets->vrsave_offset, 4);
+
+      return;
+    }
+
+  offset = rs6000_aix_get_vrreg_offset (tdep, offsets, regnum);
+  if (regnum != tdep->ppc_vrsave_regnum
+      && regnum != tdep->ppc_vrsave_regnum - 1)
+    ppc_collect_reg (regcache, regnum, (gdb_byte *) vrregs, offset, 16);
+  else
+    ppc_collect_reg (regcache, regnum,
+                   (gdb_byte *) vrregs, offset, 4);
+}
+
+static const struct regset rs6000_aix_vrregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vrregset,
+  rs6000_aix_collect_vrregset
+};
+
+static const struct regset rs6000_aix_vsxregset = {
+  &rs6000_aix_vrreg_offset,
+  rs6000_aix_supply_vsxregset,
+  rs6000_aix_collect_vsxregset
+};
+
 static struct trad_frame_cache *
 aix_sighandle_frame_cache (frame_info_ptr this_frame,
 			   void **this_cache)
@@ -262,10 +434,20 @@ rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
 					 const struct regcache *regcache)
 {
   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
+  int have_altivec = tdep->ppc_vr0_regnum != -1;
+  int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
   if (tdep->wordsize == 4)
     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data);
   else
     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data);
+
+  if (have_altivec)
+   cb (".aix-vmx", 560, 560, &rs6000_aix_vrregset, "AIX altivec", cb_data);
+
+  if (have_vsx)
+   cb (".aix-vsx", 256, 256, &rs6000_aix_vsxregset, "AIX vsx", cb_data);
+
 }
 
 
-- 
2.38.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-07 13:24                           ` Aditya Kamath1
@ 2023-03-07 15:53                             ` Ulrich Weigand
  2023-03-09  2:21                               ` Aditya Kamath1
  0 siblings, 1 reply; 18+ messages in thread
From: Ulrich Weigand @ 2023-03-07 15:53 UTC (permalink / raw)
  To: gdb-patches, Aditya Kamath1, simark; +Cc: Sangamesh Mallayya

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

This version is OK, I've checked it in now.

Thanks,
Ulrich


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Enable vector instruction debugging for AIX
  2023-03-07 15:53                             ` Ulrich Weigand
@ 2023-03-09  2:21                               ` Aditya Kamath1
  0 siblings, 0 replies; 18+ messages in thread
From: Aditya Kamath1 @ 2023-03-09  2:21 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches, simark; +Cc: Sangamesh Mallayya

[-- Attachment #1: Type: text/plain, Size: 924 bytes --]

Thank you Ulrich and community members for your support in this patch. We Appreciate your efforts for spending time to guide us to deliver quality for GDB and helping us learn as well.

We will come up with the kernel thread related code movements patch to rs6000-aix-nat.c from aix-thread.c in another thread in the next few days.

Have a nice day ahead.

From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Date: Tuesday, 7 March 2023 at 9:23 PM
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>, Aditya Kamath1 <Aditya.Kamath1@ibm.com>, simark@simark.ca <simark@simark.ca>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Enable vector instruction debugging for AIX
Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>Please find attached the patch. {See: 0001-Enable-vector-instruction-debugging-for-AIX.patch}.

This version is OK, I've checked it in now.

Thanks,
Ulrich

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2023-03-09  2:21 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-13 10:52 [PATCH] Enable vector instruction debugging for AIX Aditya Kamath1
2022-10-13 10:52 ` Aditya Kamath1
2022-10-14 12:41 ` Ulrich Weigand
2022-10-28 10:35   ` Aditya Kamath1
2022-10-28 12:39     ` Ulrich Weigand
2022-11-14 16:26       ` Aditya Kamath1
2022-11-15 19:03         ` Ulrich Weigand
2023-02-23 12:49           ` Aditya Kamath1
2023-02-24 15:26             ` Ulrich Weigand
2023-03-01 12:34               ` Aditya Kamath1
2023-03-03 14:59                 ` Ulrich Weigand
2023-03-06 13:45                   ` Aditya Kamath1
2023-03-07 10:25                     ` Ulrich Weigand
2023-03-07 12:13                       ` Aditya Kamath1
2023-03-07 12:55                         ` Ulrich Weigand
2023-03-07 13:24                           ` Aditya Kamath1
2023-03-07 15:53                             ` Ulrich Weigand
2023-03-09  2:21                               ` Aditya Kamath1

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).