/* GNU/Linux/ARM specific low level interface, for the remote server for GDB.
- Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ Copyright (C) 1995-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "arch/arm-linux.h"
#include "arch/arm-get-next-pcs.h"
#include "linux-aarch32-low.h"
+#include "linux-aarch32-tdesc.h"
+#include "linux-arm-tdesc.h"
#include <sys/uio.h>
/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h.
#include <signal.h>
#include <sys/syscall.h>
-/* Defined in auto-generated files. */
-void init_registers_arm (void);
-extern const struct target_desc *tdesc_arm;
-
-void init_registers_arm_with_iwmmxt (void);
-extern const struct target_desc *tdesc_arm_with_iwmmxt;
-
-void init_registers_arm_with_vfpv2 (void);
-extern const struct target_desc *tdesc_arm_with_vfpv2;
-
-void init_registers_arm_with_vfpv3 (void);
-extern const struct target_desc *tdesc_arm_with_vfpv3;
-
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 22
#endif
static void
arm_fill_wmmxregset (struct regcache *regcache, void *buf)
{
- int i;
-
- if (regcache->tdesc != tdesc_arm_with_iwmmxt)
+ if (arm_linux_get_tdesc_fp_type (regcache->tdesc) != ARM_FP_TYPE_IWMMXT)
return;
- for (i = 0; i < 16; i++)
+ for (int i = 0; i < 16; i++)
collect_register (regcache, arm_num_regs + i, (char *) buf + i * 8);
/* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */
- for (i = 0; i < 6; i++)
+ for (int i = 0; i < 6; i++)
collect_register (regcache, arm_num_regs + i + 16,
(char *) buf + 16 * 8 + i * 4);
}
static void
arm_store_wmmxregset (struct regcache *regcache, const void *buf)
{
- int i;
-
- if (regcache->tdesc != tdesc_arm_with_iwmmxt)
+ if (arm_linux_get_tdesc_fp_type (regcache->tdesc) != ARM_FP_TYPE_IWMMXT)
return;
- for (i = 0; i < 16; i++)
+ for (int i = 0; i < 16; i++)
supply_register (regcache, arm_num_regs + i, (char *) buf + i * 8);
/* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */
- for (i = 0; i < 6; i++)
+ for (int i = 0; i < 6; i++)
supply_register (regcache, arm_num_regs + i + 16,
(char *) buf + 16 * 8 + i * 4);
}
{
int num;
- if (regcache->tdesc == tdesc_arm_with_neon
- || regcache->tdesc == tdesc_arm_with_vfpv3)
+ if (is_aarch32_linux_description (regcache->tdesc))
num = 32;
- else if (regcache->tdesc == tdesc_arm_with_vfpv2)
- num = 16;
else
- return;
+ {
+ arm_fp_type fp_type = arm_linux_get_tdesc_fp_type (regcache->tdesc);
+
+ if (fp_type == ARM_FP_TYPE_VFPV3)
+ num = 32;
+ else if (fp_type == ARM_FP_TYPE_VFPV2)
+ num = 16;
+ else
+ return;
+ }
arm_fill_vfpregset_num (regcache, buf, num);
}
{
int num;
- if (regcache->tdesc == tdesc_arm_with_neon
- || regcache->tdesc == tdesc_arm_with_vfpv3)
+ if (is_aarch32_linux_description (regcache->tdesc))
num = 32;
- else if (regcache->tdesc == tdesc_arm_with_vfpv2)
- num = 16;
else
- return;
+ {
+ arm_fp_type fp_type = arm_linux_get_tdesc_fp_type (regcache->tdesc);
+
+ if (fp_type == ARM_FP_TYPE_VFPV3)
+ num = 32;
+ else if (fp_type == ARM_FP_TYPE_VFPV2)
+ num = 16;
+ else
+ return;
+ }
arm_store_vfpregset_num (regcache, buf, num);
}
return arm_is_thumb_mode ();
}
-/* Read memory from the inferiror.
+/* Read memory from the inferior.
BYTE_ORDER is ignored and there to keep compatiblity with GDB's
read_memory_unsigned_integer. */
static ULONGEST
/* Callback to mark a watch-/breakpoint to be updated in all threads of
the current process. */
-struct update_registers_data
-{
- int watch;
- int i;
-};
-
-static int
-update_registers_callback (struct inferior_list_entry *entry, void *arg)
+static void
+update_registers_callback (thread_info *thread, int watch, int i)
{
- struct thread_info *thread = (struct thread_info *) entry;
struct lwp_info *lwp = get_thread_lwp (thread);
- struct update_registers_data *data = (struct update_registers_data *) arg;
- /* Only update the threads of the current process. */
- if (pid_of (thread) == pid_of (current_thread))
- {
- /* The actual update is done later just before resuming the lwp,
- we just mark that the registers need updating. */
- if (data->watch)
- lwp->arch_private->wpts_changed[data->i] = 1;
- else
- lwp->arch_private->bpts_changed[data->i] = 1;
-
- /* If the lwp isn't stopped, force it to momentarily pause, so
- we can update its breakpoint registers. */
- if (!lwp->stopped)
- linux_stop_lwp (lwp);
- }
+ /* The actual update is done later just before resuming the lwp,
+ we just mark that the registers need updating. */
+ if (watch)
+ lwp->arch_private->wpts_changed[i] = 1;
+ else
+ lwp->arch_private->bpts_changed[i] = 1;
- return 0;
+ /* If the lwp isn't stopped, force it to momentarily pause, so
+ we can update its breakpoint registers. */
+ if (!lwp->stopped)
+ linux_stop_lwp (lwp);
}
static int
for (i = 0; i < count; i++)
if (!arm_hwbp_control_is_enabled (pts[i].control))
{
- struct update_registers_data data = { watch, i };
pts[i] = p;
- find_inferior (&all_threads, update_registers_callback, &data);
+
+ /* Only update the threads of the current process. */
+ for_each_thread (current_thread->id.pid (), [&] (thread_info *thread)
+ {
+ update_registers_callback (thread, watch, i);
+ });
+
return 0;
}
for (i = 0; i < count; i++)
if (arm_linux_hw_breakpoint_equal (&p, pts + i))
{
- struct update_registers_data data = { watch, i };
pts[i].control = arm_hwbp_control_disable (pts[i].control);
- find_inferior (&all_threads, update_registers_callback, &data);
+
+ /* Only update the threads of the current process. */
+ for_each_thread (current_thread->id.pid (), [&] (thread_info *thread)
+ {
+ update_registers_callback (thread, watch, i);
+ });
+
return 0;
}
/* Mark all the hardware breakpoints and watchpoints as changed to
make sure that the registers will be updated. */
- child_lwp = find_lwp_pid (ptid_of (child));
+ child_lwp = find_lwp_pid (ptid_t (child->pid));
child_lwp_info = child_lwp->arch_private;
for (i = 0; i < MAX_BPTS; i++)
child_lwp_info->bpts_changed[i] = 1;
return next_pc;
}
-static int
-arm_get_hwcap (unsigned long *valp)
-{
- unsigned char *data = (unsigned char *) alloca (8);
- int offset = 0;
-
- while ((*the_target->read_auxv) (offset, data, 8) == 8)
- {
- unsigned int *data_p = (unsigned int *)data;
- if (data_p[0] == AT_HWCAP)
- {
- *valp = data_p[1];
- return 1;
- }
-
- offset += 8;
- }
-
- *valp = 0;
- return 0;
-}
-
static const struct target_desc *
arm_read_description (void)
{
- int pid = lwpid_of (current_thread);
- unsigned long arm_hwcap = 0;
-
- /* Query hardware watchpoint/breakpoint capabilities. */
- arm_linux_init_hwbp_cap (pid);
-
- if (arm_get_hwcap (&arm_hwcap) == 0)
- return tdesc_arm;
+ unsigned long arm_hwcap = linux_get_hwcap (4);
if (arm_hwcap & HWCAP_IWMMXT)
- return tdesc_arm_with_iwmmxt;
+ return arm_linux_read_description (ARM_FP_TYPE_IWMMXT);
if (arm_hwcap & HWCAP_VFP)
{
- const struct target_desc *result;
- char *buf;
+ /* Make sure that the kernel supports reading VFP registers. Support was
+ added in 2.6.30. */
+ int pid = lwpid_of (current_thread);
+ errno = 0;
+ char *buf = (char *) alloca (ARM_VFP3_REGS_SIZE);
+ if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0 && errno == EIO)
+ return arm_linux_read_description (ARM_FP_TYPE_NONE);
/* NEON implies either no VFP, or VFPv3-D32. We only support
it with VFP. */
if (arm_hwcap & HWCAP_NEON)
- result = tdesc_arm_with_neon;
+ return aarch32_linux_read_description ();
else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
- result = tdesc_arm_with_vfpv3;
+ return arm_linux_read_description (ARM_FP_TYPE_VFPV3);
else
- result = tdesc_arm_with_vfpv2;
-
- /* Now make sure that the kernel supports reading these
- registers. Support was added in 2.6.30. */
- errno = 0;
- buf = (char *) xmalloc (32 * 8 + 4);
- if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
- && errno == EIO)
- result = tdesc_arm;
-
- free (buf);
-
- return result;
+ return arm_linux_read_description (ARM_FP_TYPE_VFPV2);
}
/* The default configuration uses legacy FPA registers, probably
simulated. */
- return tdesc_arm;
+ return arm_linux_read_description (ARM_FP_TYPE_NONE);
}
static void
int gpregs[18];
struct iovec iov;
+ /* Query hardware watchpoint/breakpoint capabilities. */
+ arm_linux_init_hwbp_cap (tid);
+
current_process ()->tdesc = arm_read_description ();
iov.iov_base = gpregs;
/* Register sets without using PTRACE_GETREGSET. */
static struct regset_info arm_regsets[] = {
- { PTRACE_GETREGS, PTRACE_SETREGS, 0, 18 * 4,
- GENERAL_REGS,
+ { PTRACE_GETREGS, PTRACE_SETREGS, 0,
+ ARM_CORE_REGS_SIZE + ARM_INT_REGISTER_SIZE, GENERAL_REGS,
arm_fill_gregset, arm_store_gregset },
- { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 0, 16 * 8 + 6 * 4,
- EXTENDED_REGS,
+ { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 0, IWMMXT_REGS_SIZE, EXTENDED_REGS,
arm_fill_wmmxregset, arm_store_wmmxregset },
- { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 0, 32 * 8 + 4,
- EXTENDED_REGS,
+ { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 0, ARM_VFP3_REGS_SIZE, EXTENDED_REGS,
arm_fill_vfpregset, arm_store_vfpregset },
NULL_REGSET
};
const struct target_desc *tdesc = current_process ()->tdesc;
if (have_ptrace_getregset == 1
- && (tdesc == tdesc_arm_with_neon || tdesc == tdesc_arm_with_vfpv3))
+ && (is_aarch32_linux_description (tdesc)
+ || arm_linux_get_tdesc_fp_type (tdesc) == ARM_FP_TYPE_VFPV3))
return ®s_info_aarch32;
- else
- return ®s_info_arm;
+
+ return ®s_info_arm;
}
struct linux_target_ops the_low_target = {
void
initialize_low_arch (void)
{
- /* Initialize the Linux target descriptions. */
- init_registers_arm ();
- init_registers_arm_with_iwmmxt ();
- init_registers_arm_with_vfpv2 ();
- init_registers_arm_with_vfpv3 ();
-
initialize_low_arch_aarch32 ();
-
initialize_regsets_info (&arm_regsets_info);
}