- if ((regno == -1) || regno == gdbarch_pc_regnum (current_gdbarch))
- right_fill_reg (regcache, gdbarch_pc_regnum (current_gdbarch),
- regp + PT_NIP);
- if ((regno == -1) || regno == tdep->ppc_lr_regnum)
- right_fill_reg (regcache, tdep->ppc_lr_regnum, regp + PT_LNK);
- if ((regno == -1) || regno == tdep->ppc_cr_regnum)
- regcache_raw_collect (regcache, tdep->ppc_cr_regnum,
- regp + PT_CCR);
- if ((regno == -1) || regno == tdep->ppc_xer_regnum)
- regcache_raw_collect (regcache, tdep->ppc_xer_regnum,
- regp + PT_XER);
- if ((regno == -1) || regno == tdep->ppc_ctr_regnum)
- right_fill_reg (regcache, tdep->ppc_ctr_regnum, regp + PT_CTR);
-#ifdef PT_MQ
- if (((regno == -1) || regno == tdep->ppc_mq_regnum)
- && (tdep->ppc_mq_regnum != -1))
- right_fill_reg (regcache, tdep->ppc_mq_regnum, regp + PT_MQ);
-#endif
- if ((regno == -1) || regno == tdep->ppc_ps_regnum)
- right_fill_reg (regcache, tdep->ppc_ps_regnum, regp + PT_MSR);
+ return ret;
+}
+
+static void
+ppc_linux_new_thread (struct lwp_info *lp)
+{
+ int tid = ptid_get_lwp (lp->ptid);
+
+ if (have_ptrace_hwdebug_interface ())
+ {
+ int i;
+ struct thread_points *p;
+ struct hw_break_tuple *hw_breaks;
+
+ if (VEC_empty (thread_points_p, ppc_threads))
+ return;
+
+ /* Get a list of breakpoints from any thread. */
+ p = VEC_last (thread_points_p, ppc_threads);
+ hw_breaks = p->hw_breaks;
+
+ /* Copy that thread's breakpoints and watchpoints to the new thread. */
+ for (i = 0; i < max_slots_number; i++)
+ if (hw_breaks[i].hw_break)
+ {
+ /* Older kernels did not make new threads inherit their parent
+ thread's debug state, so we always clear the slot and replicate
+ the debug state ourselves, ensuring compatibility with all
+ kernels. */
+
+ /* The ppc debug resource accounting is done through "slots".
+ Ask the kernel the deallocate this specific *point's slot. */
+ ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot);
+
+ hwdebug_insert_point (hw_breaks[i].hw_break, tid);
+ }
+ }
+ else
+ ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value);
+}
+
+static void
+ppc_linux_thread_exit (struct thread_info *tp, int silent)
+{
+ int i;
+ int tid = ptid_get_lwp (tp->ptid);
+ struct hw_break_tuple *hw_breaks;
+ struct thread_points *t = NULL, *p;
+
+ if (!have_ptrace_hwdebug_interface ())
+ return;
+
+ for (i = 0; VEC_iterate (thread_points_p, ppc_threads, i, p); i++)
+ if (p->tid == tid)
+ {
+ t = p;
+ break;
+ }
+
+ if (t == NULL)
+ return;
+
+ VEC_unordered_remove (thread_points_p, ppc_threads, i);
+
+ hw_breaks = t->hw_breaks;
+
+ for (i = 0; i < max_slots_number; i++)
+ if (hw_breaks[i].hw_break)
+ xfree (hw_breaks[i].hw_break);
+
+ xfree (t->hw_breaks);
+ xfree (t);
+}
+
+static int
+ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+{
+ siginfo_t siginfo;
+
+ if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
+ return 0;
+
+ if (siginfo.si_signo != SIGTRAP
+ || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+ return 0;
+
+ if (have_ptrace_hwdebug_interface ())
+ {
+ int i;
+ struct thread_points *t;
+ struct hw_break_tuple *hw_breaks;
+ /* The index (or slot) of the *point is passed in the si_errno field. */
+ int slot = siginfo.si_errno;
+
+ t = hwdebug_find_thread_points_by_tid (ptid_get_lwp (inferior_ptid), 0);
+
+ /* Find out if this *point is a hardware breakpoint.
+ If so, we should return 0. */
+ if (t)
+ {
+ hw_breaks = t->hw_breaks;
+ for (i = 0; i < max_slots_number; i++)
+ if (hw_breaks[i].hw_break && hw_breaks[i].slot == slot
+ && hw_breaks[i].hw_break->trigger_type
+ == PPC_BREAKPOINT_TRIGGER_EXECUTE)
+ return 0;
+ }
+ }
+
+ *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
+ return 1;
+}
+
+static int
+ppc_linux_stopped_by_watchpoint (struct target_ops *ops)
+{
+ CORE_ADDR addr;
+ return ppc_linux_stopped_data_address (ops, &addr);
+}
+
+static int
+ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
+ CORE_ADDR addr,
+ CORE_ADDR start, int length)
+{
+ int mask;
+
+ if (have_ptrace_hwdebug_interface ()
+ && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ return start <= addr && start + length >= addr;
+ else if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+ mask = 3;
+ else
+ mask = 7;
+
+ addr &= ~mask;
+
+ /* Check whether [start, start+length-1] intersects [addr, addr+mask]. */
+ return start <= addr + mask && start + length - 1 >= addr;
+}
+
+/* Return the number of registers needed for a masked hardware watchpoint. */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+ CORE_ADDR addr, CORE_ADDR mask)
+{
+ if (!have_ptrace_hwdebug_interface ()
+ || (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+ return -1;
+ else if ((mask & 0xC0000000) != 0xC0000000)
+ {
+ warning (_("The given mask covers kernel address space "
+ "and cannot be used.\n"));
+
+ return -2;
+ }
+ else
+ return 2;
+}
+
+static void
+ppc_linux_store_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ pid_t tid = get_ptrace_pid (regcache_get_ptid (regcache));
+
+ if (regno >= 0)
+ store_register (regcache, tid, regno);
+ else
+ store_ppc_registers (regcache, tid);
+}
+
+/* Functions for transferring registers between a gregset_t or fpregset_t
+ (see sys/ucontext.h) and gdb's regcache. The word size is that used
+ by the ptrace interface, not the current program's ABI. Eg. if a
+ powerpc64-linux gdb is being used to debug a powerpc32-linux app, we
+ read or write 64-bit gregsets. This is to suit the host libthread_db. */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+ const struct regset *regset = ppc_linux_gregset (sizeof (long));
+
+ ppc_supply_gregset (regset, regcache, -1, gregsetp, sizeof (*gregsetp));
+}
+
+void
+fill_gregset (const struct regcache *regcache,
+ gdb_gregset_t *gregsetp, int regno)
+{
+ const struct regset *regset = ppc_linux_gregset (sizeof (long));
+
+ if (regno == -1)
+ memset (gregsetp, 0, sizeof (*gregsetp));
+ ppc_collect_gregset (regset, regcache, regno, gregsetp, sizeof (*gregsetp));