+ /* 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;
+
+ gdb_assert (sizeof (evrregs.evr[0])
+ == register_size (current_gdbarch, tdep->ppc_ev0_upper_regnum));
+ gdb_assert (sizeof (evrregs.acc)
+ == register_size (current_gdbarch, tdep->ppc_acc_regnum));
+ gdb_assert (sizeof (evrregs.spefscr)
+ == register_size (current_gdbarch, tdep->ppc_spefscr_regnum));
+
+ if (regno == -1)
+ /* Since we're going to write out every register, the code below
+ should store to every field of evrregs; if that doesn't happen,
+ make it obvious by initializing it with suspicious values. */
+ memset (&evrregs, 42, sizeof (evrregs));
+ else
+ /* We can only read and write the entire EVR register set at a
+ time, so to write just a single register, we do a
+ read-modify-write maneuver. */
+ get_spe_registers (tid, &evrregs);
+
+ if (regno == -1)
+ {
+ int i;
+
+ for (i = 0; i < ppc_num_gprs; i++)
+ regcache_raw_collect (regcache,
+ tdep->ppc_ev0_upper_regnum + i,
+ &evrregs.evr[i]);
+ }
+ else if (tdep->ppc_ev0_upper_regnum <= regno
+ && regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs)
+ regcache_raw_collect (regcache, regno,
+ &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
+
+ if (regno == -1
+ || regno == tdep->ppc_acc_regnum)
+ regcache_raw_collect (regcache,
+ tdep->ppc_acc_regnum,
+ &evrregs.acc);
+
+ if (regno == -1
+ || regno == tdep->ppc_spefscr_regnum)
+ regcache_raw_collect (regcache,
+ tdep->ppc_spefscr_regnum,
+ &evrregs.spefscr);
+
+ /* Write back the modified register set. */
+ set_spe_registers (tid, &evrregs);
+}
+
+static void
+store_register (const struct regcache *regcache, int tid, int regno)
+{
+ 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 i;
+ size_t bytes_to_transfer;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (altivec_register_p (regno))
+ {
+ store_altivec_register (regcache, tid, regno);
+ return;
+ }
+ else if (spe_register_p (regno))
+ {
+ store_spe_register (regcache, tid, regno);
+ return;
+ }
+
+ if (regaddr == -1)
+ return;
+
+ /* First collect the register. Keep in mind that the regcache's
+ idea of the register's size may not be a multiple of sizeof
+ (long). */
+ memset (buf, 0, sizeof buf);
+ bytes_to_transfer = align_up (register_size (current_gdbarch, regno),
+ sizeof (long));
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+ {
+ /* Little-endian values always sit at the left end of the buffer. */
+ regcache_raw_collect (regcache, regno, buf);
+ }
+ else if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ {
+ /* Big-endian values sit at the right end of the buffer. */
+ size_t padding = (bytes_to_transfer
+ - register_size (current_gdbarch, regno));
+ regcache_raw_collect (regcache, regno, buf + padding);
+ }
+
+ for (i = 0; i < bytes_to_transfer; i += sizeof (long))
+ {
+ errno = 0;
+ ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr,
+ *(long *) &buf[i]);
+ regaddr += sizeof (long);
+
+ if (errno == EIO
+ && regno == tdep->ppc_fpscr_regnum)
+ {
+ /* Some older kernel versions don't allow fpscr to be written. */
+ continue;
+ }
+
+ if (errno != 0)
+ {
+ char message[128];
+ sprintf (message, "writing register %s (#%d)",
+ gdbarch_register_name (current_gdbarch, regno), regno);
+ perror_with_name (message);
+ }
+ }
+}
+
+static void
+fill_vrregset (const 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, but only VSCR is fetched as a 16 bytes quantity. */
+ if (i == (num_of_vrregs - 2))
+ regcache_raw_collect (regcache, tdep->ppc_vr0_regnum + i,
+ *vrregsetp + i * vrregsize + offset);
+ else
+ regcache_raw_collect (regcache, tdep->ppc_vr0_regnum + i,
+ *vrregsetp + i * vrregsize);
+ }
+}
+
+static void
+store_altivec_registers (const 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 (_("Couldn't get AltiVec registers"));
+ }
+
+ fill_vrregset (regcache, ®s);
+
+ if (ptrace (PTRACE_SETVRREGS, tid, 0, ®s) < 0)
+ perror_with_name (_("Couldn't write AltiVec registers"));
+}
+
+static void
+store_ppc_registers (const struct regcache *regcache, int tid)
+{
+ int i;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ for (i = 0; i < ppc_num_gprs; i++)
+ store_register (regcache, tid, tdep->ppc_gp0_regnum + i);
+ if (tdep->ppc_fp0_regnum >= 0)
+ for (i = 0; i < ppc_num_fprs; i++)
+ store_register (regcache, tid, tdep->ppc_fp0_regnum + i);
+ store_register (regcache, tid, PC_REGNUM);
+ if (tdep->ppc_ps_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_ps_regnum);
+ if (tdep->ppc_cr_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_cr_regnum);
+ if (tdep->ppc_lr_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_lr_regnum);
+ if (tdep->ppc_ctr_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_ctr_regnum);
+ if (tdep->ppc_xer_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_xer_regnum);
+ if (tdep->ppc_mq_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_mq_regnum);
+ if (tdep->ppc_fpscr_regnum != -1)
+ store_register (regcache, tid, tdep->ppc_fpscr_regnum);
+ if (have_ptrace_getvrregs)
+ if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
+ store_altivec_registers (regcache, tid);
+ if (tdep->ppc_ev0_upper_regnum >= 0)
+ store_spe_register (regcache, tid, -1);
+}
+
+static int
+ppc_linux_check_watch_resources (int type, int cnt, int ot)
+{
+ int tid;
+ ptid_t ptid = inferior_ptid;
+
+ /* DABR (data address breakpoint register) is optional for PPC variants.
+ Some variants have one DABR, others have none. So CNT can't be larger
+ than 1. */
+ if (cnt > 1)
+ return 0;
+
+ /* We need to know whether ptrace supports PTRACE_SET_DEBUGREG and whether
+ the target has DABR. If either answer is no, the ptrace call will
+ return -1. Fail in that case. */
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
+ return 0;
+ return 1;
+}
+
+static int
+ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ /* Handle sub-8-byte quantities. */
+ if (len <= 0)
+ return 0;
+
+ /* addr+len must fall in the 8 byte watchable region. */
+ if ((addr + len) > (addr & ~7) + 8)
+ return 0;
+
+ return 1;
+}
+
+/* Set a watchpoint of type TYPE at address ADDR. */
+static int
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ int tid;
+ long dabr_value;
+ ptid_t ptid = inferior_ptid;
+
+ dabr_value = addr & ~7;
+ switch (rw)
+ {
+ case hw_read:
+ /* Set read and translate bits. */
+ dabr_value |= 5;
+ break;
+ case hw_write:
+ /* Set write and translate bits. */
+ dabr_value |= 6;
+ break;
+ case hw_access:
+ /* Set read, write and translate bits. */
+ dabr_value |= 7;
+ break;
+ }
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value);
+}
+
+static int
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ int tid;
+ ptid_t ptid = inferior_ptid;
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0);
+}
+
+static int
+ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+{
+ if (last_stopped_data_address)
+ {
+ *addr_p = last_stopped_data_address;
+ last_stopped_data_address = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc_linux_stopped_by_watchpoint (void)
+{
+ int tid;
+ struct siginfo siginfo;
+ ptid_t ptid = inferior_ptid;
+ CORE_ADDR *addr_p;
+
+ tid = TIDGET(ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ errno = 0;
+ ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+
+ if (errno != 0 || siginfo.si_signo != SIGTRAP ||
+ (siginfo.si_code & 0xffff) != 0x0004)
+ return 0;
+
+ last_stopped_data_address = (uintptr_t) siginfo.si_addr;
+ return 1;
+}
+
+static void
+ppc_linux_store_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 >= 0)
+ store_register (regcache, tid, regno);
+ else
+ store_ppc_registers (regcache, tid);