+/* Wrapper functions for the standard regset handling, used by
+ thread debugging. */
+
+void
+fill_gregset (const struct regcache *regcache,
+ gdb_gregset_t *gregsetp, int regno)
+{
+ arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
+}
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+ arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
+}
+
+void
+fill_fpregset (const struct regcache *regcache,
+ gdb_fpregset_t *fpregsetp, int regno)
+{
+ arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
+}
+
+/* Fill GDB's register array with the floating-point register values
+ in *fpregsetp. */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+ arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
+}
+
+/* Fetch the thread-local storage pointer for libthread_db. */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base)
+{
+ if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
+ return PS_ERR;
+
+ /* IDX is the bias from the thread pointer to the beginning of the
+ thread descriptor. It has to be subtracted due to implementation
+ quirks in libthread_db. */
+ *base = (void *) ((char *)*base - idx);
+
+ return PS_OK;
+}
+
+static const struct target_desc *
+arm_linux_read_description (struct target_ops *ops)
+{
+ CORE_ADDR arm_hwcap = 0;
+
+ if (have_ptrace_getregset == TRIBOOL_UNKNOWN)
+ {
+ elf_gregset_t gpregs;
+ struct iovec iov;
+ int tid = ptid_get_lwp (inferior_ptid);
+
+ iov.iov_base = &gpregs;
+ iov.iov_len = sizeof (gpregs);
+
+ /* Check if PTRACE_GETREGSET works. */
+ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) < 0)
+ have_ptrace_getregset = TRIBOOL_FALSE;
+ else
+ have_ptrace_getregset = TRIBOOL_TRUE;
+ }
+
+ if (target_auxv_search (ops, AT_HWCAP, &arm_hwcap) != 1)
+ {
+ return ops->beneath->to_read_description (ops->beneath);
+ }
+
+ if (arm_hwcap & HWCAP_IWMMXT)
+ return tdesc_arm_with_iwmmxt;
+
+ if (arm_hwcap & HWCAP_VFP)
+ {
+ int pid;
+ char *buf;
+ const struct target_desc * result = NULL;
+
+ /* NEON implies VFPv3-D32 or no-VFP unit. Say that we only support
+ Neon with VFPv3-D32. */
+ if (arm_hwcap & HWCAP_NEON)
+ result = tdesc_arm_with_neon;
+ else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+ result = tdesc_arm_with_vfpv3;
+ else
+ result = tdesc_arm_with_vfpv2;
+
+ /* Now make sure that the kernel supports reading these
+ registers. Support was added in 2.6.30. */
+ pid = ptid_get_lwp (inferior_ptid);
+ errno = 0;
+ buf = (char *) alloca (VFP_REGS_SIZE);
+ if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
+ && errno == EIO)
+ result = NULL;
+
+ return result;
+ }
+
+ return ops->beneath->to_read_description (ops->beneath);
+}
+
+/* Information describing the hardware breakpoint capabilities. */
+struct arm_linux_hwbp_cap
+{
+ gdb_byte arch;
+ gdb_byte max_wp_length;
+ gdb_byte wp_count;
+ gdb_byte bp_count;
+};
+
+/* Since we cannot dynamically allocate subfields of arm_linux_process_info,
+ assume a maximum number of supported break-/watchpoints. */
+#define MAX_BPTS 16
+#define MAX_WPTS 16
+
+/* Get hold of the Hardware Breakpoint information for the target we are
+ attached to. Returns NULL if the kernel doesn't support Hardware
+ breakpoints at all, or a pointer to the information structure. */
+static const struct arm_linux_hwbp_cap *
+arm_linux_get_hwbp_cap (void)
+{
+ /* The info structure we return. */
+ static struct arm_linux_hwbp_cap info;
+
+ /* Is INFO in a good state? -1 means that no attempt has been made to
+ initialize INFO; 0 means an attempt has been made, but it failed; 1
+ means INFO is in an initialized state. */
+ static int available = -1;
+
+ if (available == -1)