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

