+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr = ppc_register_u_addr (regno);
+ int bytes_transferred;
+ unsigned int offset; /* Offset of registers within the u area. */
+ char buf[MAX_REGISTER_SIZE];
+
+ if (altivec_register_p (regno))
+ {
+ /* If this is the first time through, or if it is not the first
+ time through, and we have comfirmed that there is kernel
+ support for such a ptrace request, then go and fetch the
+ register. */
+ if (have_ptrace_getvrregs)
+ {
+ fetch_altivec_register (regcache, tid, regno);
+ return;
+ }
+ /* If we have discovered that there is no ptrace support for
+ AltiVec registers, fall through and return zeroes, because
+ regaddr will be -1 in this case. */
+ }
+ else if (spe_register_p (regno))
+ {
+ fetch_spe_register (regcache, tid, regno);
+ return;
+ }
+
+ if (regaddr == -1)
+ {
+ memset (buf, '\0', register_size (current_gdbarch, regno)); /* Supply zeroes */
+ regcache_raw_supply (regcache, regno, buf);
+ return;
+ }
+
+ /* Read the raw register using sizeof(long) sized chunks. On a
+ 32-bit platform, 64-bit floating-point registers will require two
+ transfers. */
+ for (bytes_transferred = 0;
+ bytes_transferred < register_size (current_gdbarch, regno);
+ bytes_transferred += sizeof (long))
+ {
+ errno = 0;
+ *(long *) &buf[bytes_transferred]
+ = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
+ regaddr += sizeof (long);
+ if (errno != 0)
+ {
+ char message[128];
+ sprintf (message, "reading register %s (#%d)",
+ gdbarch_register_name (current_gdbarch, regno), regno);
+ perror_with_name (message);
+ }
+ }
+
+ /* Now supply the register. Keep in mind that the regcache's idea
+ of the register's size may not be a multiple of sizeof
+ (long). */
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+ {
+ /* Little-endian values are always found at the left end of the
+ bytes transferred. */
+ regcache_raw_supply (regcache, regno, buf);
+ }
+ else if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ {
+ /* Big-endian values are found at the right end of the bytes
+ transferred. */
+ size_t padding = (bytes_transferred
+ - register_size (current_gdbarch, regno));
+ regcache_raw_supply (regcache, regno, buf + padding);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ _("fetch_register: unexpected byte order: %d"),
+ gdbarch_byte_order (current_gdbarch));
+}
+
+static void
+supply_vrregset (struct regcache *regcache, gdb_vrregset_t *vrregsetp)
+{
+ int i;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
+ int vrregsize = register_size (current_gdbarch, tdep->ppc_vr0_regnum);
+ int offset = vrregsize - register_size (current_gdbarch, tdep->ppc_vrsave_regnum);
+
+ for (i = 0; i < num_of_vrregs; i++)
+ {
+ /* The last 2 registers of this set are only 32 bit long, not
+ 128. However an offset is necessary only for VSCR because it
+ occupies a whole vector, while VRSAVE occupies a full 4 bytes
+ slot. */
+ if (i == (num_of_vrregs - 2))
+ regcache_raw_supply (regcache, tdep->ppc_vr0_regnum + i,
+ *vrregsetp + i * vrregsize + offset);
+ else
+ regcache_raw_supply (regcache, tdep->ppc_vr0_regnum + i,
+ *vrregsetp + i * vrregsize);
+ }
+}
+
+static void
+fetch_altivec_registers (struct regcache *regcache, int tid)
+{
+ int ret;
+ gdb_vrregset_t regs;
+
+ ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
+ if (ret < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getvrregs = 0;
+ return;
+ }
+ perror_with_name (_("Unable to fetch AltiVec registers"));
+ }
+ supply_vrregset (regcache, ®s);
+}
+
+static void
+fetch_ppc_registers (struct regcache *regcache, int tid)
+{
+ int i;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ for (i = 0; i < ppc_num_gprs; i++)
+ fetch_register (regcache, tid, tdep->ppc_gp0_regnum + i);
+ if (tdep->ppc_fp0_regnum >= 0)
+ for (i = 0; i < ppc_num_fprs; i++)
+ fetch_register (regcache, tid, tdep->ppc_fp0_regnum + i);
+ fetch_register (regcache, tid, gdbarch_pc_regnum (current_gdbarch));
+ if (tdep->ppc_ps_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_ps_regnum);
+ if (tdep->ppc_cr_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_cr_regnum);
+ if (tdep->ppc_lr_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_lr_regnum);
+ if (tdep->ppc_ctr_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_ctr_regnum);
+ if (tdep->ppc_xer_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_xer_regnum);
+ if (tdep->ppc_mq_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_mq_regnum);
+ if (tdep->ppc_fpscr_regnum != -1)
+ fetch_register (regcache, tid, tdep->ppc_fpscr_regnum);
+ if (have_ptrace_getvrregs)
+ if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+ fetch_altivec_registers (regcache, tid);
+ if (tdep->ppc_ev0_upper_regnum >= 0)
+ fetch_spe_register (regcache, tid, -1);
+}
+
+/* Fetch registers from the child process. Fetch all registers if
+ regno == -1, otherwise fetch all general registers or all floating
+ point registers depending upon the value of regno. */
+static void
+ppc_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
+{
+ /* Overload thread id onto process id */
+ int tid = TIDGET (inferior_ptid);
+
+ /* No thread id, just use process id */
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid);
+
+ if (regno == -1)
+ fetch_ppc_registers (regcache, tid);
+ else
+ fetch_register (regcache, tid, regno);
+}
+
+/* Store one register. */
+static void
+store_altivec_register (const struct regcache *regcache, int tid, int regno)
+{
+ int ret;
+ int offset = 0;
+ gdb_vrregset_t regs;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int vrregsize = register_size (current_gdbarch, tdep->ppc_vr0_regnum);
+
+ ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
+ if (ret < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getvrregs = 0;
+ return;
+ }
+ perror_with_name (_("Unable to fetch AltiVec register"));
+ }
+
+ /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes
+ long on the hardware. */
+ if (regno == (tdep->ppc_vrsave_regnum - 1))
+ offset = vrregsize - register_size (current_gdbarch, tdep->ppc_vrsave_regnum);
+
+ regcache_raw_collect (regcache, regno,
+ regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset);
+
+ ret = ptrace (PTRACE_SETVRREGS, tid, 0, ®s);
+ if (ret < 0)
+ perror_with_name (_("Unable to store AltiVec register"));
+}
+
+/* Assuming TID referrs to an SPE process, set the top halves of TID's
+ general-purpose registers and its SPE-specific registers to the
+ values in EVRREGSET. If we don't support PTRACE_SETEVRREGS, do
+ nothing.
+
+ All the logic to deal with whether or not the PTRACE_GETEVRREGS and
+ PTRACE_SETEVRREGS requests are supported is isolated here, and in
+ get_spe_registers. */
+static void
+set_spe_registers (int tid, struct gdb_evrregset_t *evrregset)
+{
+ if (have_ptrace_getsetevrregs)
+ {
+ if (ptrace (PTRACE_SETEVRREGS, tid, 0, evrregset) >= 0)
+ return;
+ else
+ {
+ /* EIO means that the PTRACE_SETEVRREGS request isn't
+ supported; we fail silently, and don't try the call
+ again. */
+ if (errno == EIO)
+ have_ptrace_getsetevrregs = 0;
+ else
+ /* Anything else needs to be reported. */
+ perror_with_name (_("Unable to set SPE registers"));
+ }
+ }
+}
+
+/* Write GDB's value for the SPE-specific raw register REGNO to TID.
+ If REGNO is -1, write the values of all the SPE-specific
+ registers. */
+static void
+store_spe_register (const struct regcache *regcache, int tid, int regno)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdb_evrregset_t evrregs;