/* GNU/Linux on ARM target support.
- Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "target.h"
#include "value.h"
#include "gdbtypes.h"
-#include "floatformat.h"
#include "gdbcore.h"
#include "frame.h"
#include "regcache.h"
-#include "doublest.h"
#include "solib-svr4.h"
#include "osabi.h"
#include "regset.h"
#include "auxv.h"
#include "xml-syscall.h"
+#include "aarch32-tdep.h"
#include "arch/arm.h"
#include "arch/arm-get-next-pcs.h"
#include "arch/arm-linux.h"
#include "user-regs.h"
#include <ctype.h>
#include "elf/common.h"
-extern int arm_apcs_32;
/* Under ARM GNU/Linux the traditional way of performing a breakpoint
is to execute a particular software interrupt, rather than use a
SoftVFP or VFP (which implies EABI) then the PC is at offset 9 in the
buffer. This is also true for the SoftFPA model. However, for the FPA
model the PC is at offset 21 in the buffer. */
-#define ARM_LINUX_JB_ELEMENT_SIZE INT_REGISTER_SIZE
+#define ARM_LINUX_JB_ELEMENT_SIZE ARM_INT_REGISTER_SIZE
#define ARM_LINUX_JB_PC_FPA 21
#define ARM_LINUX_JB_PC_EABI 9
SIGTRAMP_FRAME,
4,
{
- { ARM_LINUX_SIGRETURN_INSTR, -1 },
+ { ARM_LINUX_SIGRETURN_INSTR, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_sigreturn_init
SIGTRAMP_FRAME,
4,
{
- { ARM_LINUX_RT_SIGRETURN_INSTR, -1 },
+ { ARM_LINUX_RT_SIGRETURN_INSTR, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_rt_sigreturn_init
SIGTRAMP_FRAME,
4,
{
- { ARM_SET_R7_SIGRETURN, -1 },
- { ARM_EABI_SYSCALL, -1 },
+ { ARM_SET_R7_SIGRETURN, ULONGEST_MAX },
+ { ARM_EABI_SYSCALL, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_sigreturn_init
SIGTRAMP_FRAME,
4,
{
- { ARM_SET_R7_RT_SIGRETURN, -1 },
- { ARM_EABI_SYSCALL, -1 },
+ { ARM_SET_R7_RT_SIGRETURN, ULONGEST_MAX },
+ { ARM_EABI_SYSCALL, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_rt_sigreturn_init
SIGTRAMP_FRAME,
2,
{
- { THUMB2_SET_R7_SIGRETURN1, -1 },
- { THUMB2_SET_R7_SIGRETURN2, -1 },
- { THUMB2_EABI_SYSCALL, -1 },
+ { THUMB2_SET_R7_SIGRETURN1, ULONGEST_MAX },
+ { THUMB2_SET_R7_SIGRETURN2, ULONGEST_MAX },
+ { THUMB2_EABI_SYSCALL, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_sigreturn_init
SIGTRAMP_FRAME,
2,
{
- { THUMB2_SET_R7_RT_SIGRETURN1, -1 },
- { THUMB2_SET_R7_RT_SIGRETURN2, -1 },
- { THUMB2_EABI_SYSCALL, -1 },
+ { THUMB2_SET_R7_RT_SIGRETURN1, ULONGEST_MAX },
+ { THUMB2_SET_R7_RT_SIGRETURN2, ULONGEST_MAX },
+ { THUMB2_EABI_SYSCALL, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_rt_sigreturn_init
NORMAL_FRAME,
4,
{
- { ARM_OABI_SYSCALL_RESTART_SYSCALL, -1 },
- { ARM_LDR_PC_SP_12, -1 },
+ { ARM_OABI_SYSCALL_RESTART_SYSCALL, ULONGEST_MAX },
+ { ARM_LDR_PC_SP_12, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_restart_syscall_init
NORMAL_FRAME,
4,
{
- { ARM_OABI_SYSCALL_RESTART_SYSCALL, -1 },
- { ARM_LDR_PC_SP_4, -1 },
+ { ARM_OABI_SYSCALL_RESTART_SYSCALL, ULONGEST_MAX },
+ { ARM_LDR_PC_SP_4, ULONGEST_MAX },
{ TRAMP_SENTINEL_INSN }
},
arm_linux_restart_syscall_init
/* Core file and register set support. */
-#define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE)
+#define ARM_LINUX_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
void
arm_linux_supply_gregset (const struct regset *regset,
struct regcache *regcache,
int regnum, const void *gregs_buf, size_t len)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
int regno;
CORE_ADDR reg_pc;
- gdb_byte pc_buf[INT_REGISTER_SIZE];
+ gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
- regcache_raw_supply (regcache, regno,
- gregs + INT_REGISTER_SIZE * regno);
+ regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
if (regnum == ARM_PS_REGNUM || regnum == -1)
{
if (arm_apcs_32)
- regcache_raw_supply (regcache, ARM_PS_REGNUM,
- gregs + INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
+ regcache->raw_supply (ARM_PS_REGNUM,
+ gregs + ARM_INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
else
- regcache_raw_supply (regcache, ARM_PS_REGNUM,
- gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+ regcache->raw_supply (ARM_PS_REGNUM,
+ gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
}
if (regnum == ARM_PC_REGNUM || regnum == -1)
{
- reg_pc = extract_unsigned_integer (gregs
- + INT_REGISTER_SIZE * ARM_PC_REGNUM,
- INT_REGISTER_SIZE, byte_order);
+ reg_pc = extract_unsigned_integer (
+ gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM,
+ ARM_INT_REGISTER_SIZE, byte_order);
reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
- store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, byte_order, reg_pc);
- regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf);
+ store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
+ reg_pc);
+ regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
}
}
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
- regcache_raw_collect (regcache, regno,
- gregs + INT_REGISTER_SIZE * regno);
+ regcache->raw_collect (regno,
+ gregs + ARM_INT_REGISTER_SIZE * regno);
if (regnum == ARM_PS_REGNUM || regnum == -1)
{
if (arm_apcs_32)
- regcache_raw_collect (regcache, ARM_PS_REGNUM,
- gregs + INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
+ regcache->raw_collect (ARM_PS_REGNUM,
+ gregs + ARM_INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
else
- regcache_raw_collect (regcache, ARM_PS_REGNUM,
- gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+ regcache->raw_collect (ARM_PS_REGNUM,
+ gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
}
if (regnum == ARM_PC_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, ARM_PC_REGNUM,
- gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+ regcache->raw_collect (ARM_PC_REGNUM,
+ gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
}
/* Support for register format used by the NWFPE FPA emulator. */
{
const gdb_byte *reg_data;
gdb_byte reg_tag;
- gdb_byte buf[FP_REGISTER_SIZE];
+ gdb_byte buf[ARM_FP_REGISTER_SIZE];
- reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE;
+ reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE;
reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
- memset (buf, 0, FP_REGISTER_SIZE);
+ memset (buf, 0, ARM_FP_REGISTER_SIZE);
switch (reg_tag)
{
break;
}
- regcache_raw_supply (regcache, regno, buf);
+ regcache->raw_supply (regno, buf);
}
void
{
gdb_byte *reg_data;
gdb_byte reg_tag;
- gdb_byte buf[FP_REGISTER_SIZE];
+ gdb_byte buf[ARM_FP_REGISTER_SIZE];
- regcache_raw_collect (regcache, regno, buf);
+ regcache->raw_collect (regno, buf);
/* NOTE drow/2006-06-07: This code uses the tag already in the
register buffer. I've preserved that when moving the code
from the native file to the target file. But this doesn't
always make sense. */
- reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE;
+ reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE;
reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
switch (reg_tag)
int regno;
if (regnum == ARM_FPS_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, ARM_FPS_REGNUM,
+ regcache->raw_supply (ARM_FPS_REGNUM,
regs + NWFPE_FPSR_OFFSET);
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
collect_nwfpe_register (regcache, regno, regs);
if (regnum == ARM_FPS_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, ARM_FPS_REGNUM,
- regs + INT_REGISTER_SIZE * ARM_FPS_REGNUM);
+ regcache->raw_collect (ARM_FPS_REGNUM,
+ regs + ARM_INT_REGISTER_SIZE * ARM_FPS_REGNUM);
}
/* Support VFP register format. */
int regno;
if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, ARM_FPSCR_REGNUM, regs + 32 * 8);
+ regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
- regcache_raw_supply (regcache, regno,
- regs + (regno - ARM_D0_REGNUM) * 8);
+ regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
}
static void
int regno;
if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, ARM_FPSCR_REGNUM, regs + 32 * 8);
+ regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
- regcache_raw_collect (regcache, regno,
- regs + (regno - ARM_D0_REGNUM) * 8);
+ regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
}
static const struct regset arm_linux_gregset =
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- cb (".reg", ARM_LINUX_SIZEOF_GREGSET, &arm_linux_gregset, NULL, cb_data);
+ cb (".reg", ARM_LINUX_SIZEOF_GREGSET, ARM_LINUX_SIZEOF_GREGSET,
+ &arm_linux_gregset, NULL, cb_data);
if (tdep->vfp_register_count > 0)
- cb (".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, &arm_linux_vfpregset,
- "VFP floating-point", cb_data);
+ cb (".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, ARM_LINUX_SIZEOF_VFP,
+ &arm_linux_vfpregset, "VFP floating-point", cb_data);
else if (tdep->have_fpa_registers)
- cb (".reg2", ARM_LINUX_SIZEOF_NWFPE, &arm_linux_fpregset,
- "FPA floating-point", cb_data);
+ cb (".reg2", ARM_LINUX_SIZEOF_NWFPE, ARM_LINUX_SIZEOF_NWFPE,
+ &arm_linux_fpregset, "FPA floating-point", cb_data);
}
/* Determine target description from core file. */
struct target_ops *target,
bfd *abfd)
{
- CORE_ADDR arm_hwcap = 0;
-
- if (target_auxv_search (target, AT_HWCAP, &arm_hwcap) != 1)
- return NULL;
+ CORE_ADDR arm_hwcap = linux_get_hwcap (target);
if (arm_hwcap & HWCAP_VFP)
{
/* NEON implies VFPv3-D32 or no-VFP unit. Say that we only support
Neon with VFPv3-D32. */
if (arm_hwcap & HWCAP_NEON)
- return tdesc_arm_with_neon;
+ return aarch32_read_description ();
else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
- return tdesc_arm_with_vfpv3;
- else
- return tdesc_arm_with_vfpv2;
+ return arm_read_description (ARM_FP_TYPE_VFPV3);
+
+ return arm_read_description (ARM_FP_TYPE_VFPV2);
}
- return NULL;
+ return nullptr;
}
ULONGEST sp;
unsigned long sp_data;
CORE_ADDR next_pc = 0;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int pc_offset = 0;
int is_sigreturn = 0;
static LONGEST
arm_linux_get_syscall_number (struct gdbarch *gdbarch,
- ptid_t ptid)
+ thread_info *thread)
{
- struct regcache *regs = get_thread_regcache (ptid);
+ struct regcache *regs = get_thread_regcache (thread);
ULONGEST pc;
ULONGEST cpsr;
}
else
{
- struct gdbarch *gdbarch = get_regcache_arch (self->regcache);
+ struct gdbarch *gdbarch = self->regcache->arch ();
enum bfd_endian byte_order_for_code =
gdbarch_byte_order_for_code (gdbarch);
unsigned long this_instr =
/* Insert a single step breakpoint at the next executed instruction. */
-static VEC (CORE_ADDR) *
+static std::vector<CORE_ADDR>
arm_linux_software_single_step (struct regcache *regcache)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct arm_get_next_pcs next_pcs_ctx;
- CORE_ADDR pc;
- int i;
- VEC (CORE_ADDR) *next_pcs = NULL;
- struct cleanup *old_chain;
/* If the target does have hardware single step, GDB doesn't have
to bother software single step. */
if (target_can_do_single_step () == 1)
- return NULL;
-
- old_chain = make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs);
+ return {};
arm_get_next_pcs_ctor (&next_pcs_ctx,
&arm_linux_get_next_pcs_ops,
1,
regcache);
- next_pcs = arm_get_next_pcs (&next_pcs_ctx);
-
- for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
- {
- pc = gdbarch_addr_bits_remove (gdbarch, pc);
- VEC_replace (CORE_ADDR, next_pcs, i, pc);
- }
+ std::vector<CORE_ADDR> next_pcs = arm_get_next_pcs (&next_pcs_ctx);
- discard_cleanups (old_chain);
+ for (CORE_ADDR &pc_ref : next_pcs)
+ pc_ref = gdbarch_addr_bits_remove (gdbarch, pc_ref);
return next_pcs;
}
static void
arm_linux_cleanup_svc (struct gdbarch *gdbarch,
struct regcache *regs,
- struct displaced_step_closure *dsc)
+ arm_displaced_step_closure *dsc)
{
ULONGEST apparent_pc;
int within_scratch;
within_scratch = (apparent_pc >= dsc->scratch_base
&& apparent_pc < (dsc->scratch_base
- + DISPLACED_MODIFIED_INSNS * 4 + 4));
+ + ARM_DISPLACED_MODIFIED_INSNS * 4 + 4));
if (debug_displaced)
{
static int
arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
- struct displaced_step_closure *dsc)
+ arm_displaced_step_closure *dsc)
{
CORE_ADDR return_to = 0;
{
inferior_thread ()->control.step_resume_breakpoint
= set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame),
- bp_step_resume);
+ bp_step_resume).release ();
/* set_momentary_breakpoint invalidates FRAME. */
frame = NULL;
static void
cleanup_kernel_helper_return (struct gdbarch *gdbarch,
struct regcache *regs,
- struct displaced_step_closure *dsc)
+ arm_displaced_step_closure *dsc)
{
displaced_write_reg (regs, dsc, ARM_LR_REGNUM, dsc->tmp[0], CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->tmp[0], BRANCH_WRITE_PC);
static void
arm_catch_kernel_helper_return (struct gdbarch *gdbarch, CORE_ADDR from,
CORE_ADDR to, struct regcache *regs,
- struct displaced_step_closure *dsc)
+ arm_displaced_step_closure *dsc)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
- struct displaced_step_closure *dsc = XNEW (struct displaced_step_closure);
+ arm_displaced_step_closure *dsc = new arm_displaced_step_closure;
/* Detect when we enter an (inaccessible by GDB) Linux kernel helper, and
stop at the return location. */
regname, p->saved_arg);
++tmp;
- tmp = skip_spaces_const (tmp);
+ tmp = skip_spaces (tmp);
if (*tmp == '#' || *tmp == '$')
++tmp;
return find_solib_trampoline_target (frame, pc);
}
+/* Implement the gcc_target_options gdbarch method. */
+
+static std::string
+arm_linux_gcc_target_options (struct gdbarch *gdbarch)
+{
+ /* GCC doesn't know "-m32". */
+ return {};
+}
+
static void
arm_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
set_gdbarch_displaced_step_copy_insn (gdbarch,
arm_linux_displaced_step_copy_insn);
set_gdbarch_displaced_step_fixup (gdbarch, arm_displaced_step_fixup);
- set_gdbarch_displaced_step_free_closure (gdbarch,
- simple_displaced_step_free_closure);
set_gdbarch_displaced_step_location (gdbarch, linux_displaced_step_location);
/* Reversible debugging, process record. */
arm_linux_record_tdep.arg5 = ARM_A1_REGNUM + 4;
arm_linux_record_tdep.arg6 = ARM_A1_REGNUM + 5;
arm_linux_record_tdep.arg7 = ARM_A1_REGNUM + 6;
-}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_arm_linux_tdep;
+ set_gdbarch_gcc_target_options (gdbarch, arm_linux_gcc_target_options);
+}
void
_initialize_arm_linux_tdep (void)