/* GNU/Linux on ARM target support.
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
+ Copyright (C) 1999-2021 Free Software Foundation, Inc.
This file is part of GDB.
#include "breakpoint.h"
#include "auxv.h"
#include "xml-syscall.h"
+#include "expop.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
static const struct target_desc *
arm_linux_core_read_description (struct gdbarch *gdbarch,
- struct target_ops *target,
- bfd *abfd)
+ struct target_ops *target,
+ bfd *abfd)
{
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. */
+ 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;
}
if (svc_operand)
{
- /* OABI */
+ /* OABI */
svc_number = svc_operand - 0x900000;
}
else
{
- /* EABI */
+ /* EABI */
regcache_cooked_read_unsigned (regs, 7, &svc_number);
}
}
static void
arm_linux_cleanup_svc (struct gdbarch *gdbarch,
struct regcache *regs,
- arm_displaced_step_closure *dsc)
+ arm_displaced_step_copy_insn_closure *dsc)
{
ULONGEST apparent_pc;
int within_scratch;
&& apparent_pc < (dsc->scratch_base
+ ARM_DISPLACED_MODIFIED_INSNS * 4 + 4));
- if (debug_displaced)
- {
- fprintf_unfiltered (gdb_stdlog, "displaced: PC is apparently %.8lx after "
- "SVC step ", (unsigned long) apparent_pc);
- if (within_scratch)
- fprintf_unfiltered (gdb_stdlog, "(within scratch space)\n");
- else
- fprintf_unfiltered (gdb_stdlog, "(outside scratch space)\n");
- }
+ displaced_debug_printf ("PC is apparently %.8lx after SVC step %s",
+ (unsigned long) apparent_pc,
+ (within_scratch
+ ? "(within scratch space)"
+ : "(outside scratch space)"));
if (within_scratch)
displaced_write_reg (regs, dsc, ARM_PC_REGNUM,
static int
arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_closure *dsc)
+ arm_displaced_step_copy_insn_closure *dsc)
{
CORE_ADDR return_to = 0;
{
struct symtab_and_line sal;
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: found "
- "sigreturn/rt_sigreturn SVC call. PC in "
- "frame = %lx\n",
- (unsigned long) get_frame_pc (frame));
+ displaced_debug_printf ("found sigreturn/rt_sigreturn SVC call. "
+ "PC in frame = %lx",
+ (unsigned long) get_frame_pc (frame));
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx. "
- "Setting momentary breakpoint.\n",
- (unsigned long) return_to);
+ displaced_debug_printf ("unwind pc = %lx. Setting momentary breakpoint.",
+ (unsigned long) return_to);
gdb_assert (inferior_thread ()->control.step_resume_breakpoint
== NULL);
breakpoint set above. */
insert_breakpoints ();
}
- else if (debug_displaced)
- fprintf_unfiltered (gdb_stderr, "displaced: couldn't find previous "
- "frame to set momentary breakpoint for "
- "sigreturn/rt_sigreturn\n");
+ else
+ displaced_debug_printf ("couldn't find previous frame to set momentary "
+ "breakpoint for sigreturn/rt_sigreturn");
}
- else if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: found SVC call\n");
+ else
+ displaced_debug_printf ("found SVC call");
/* Preparation: If we detect sigreturn, set momentary breakpoint at resume
location, else nothing.
Insn: unmodified svc.
Cleanup: if pc lands in scratch space, pc <- insn_addr + insn_size
- else leave pc alone. */
+ else leave pc alone. */
dsc->cleanup = &arm_linux_cleanup_svc;
static void
cleanup_kernel_helper_return (struct gdbarch *gdbarch,
struct regcache *regs,
- arm_displaced_step_closure *dsc)
+ arm_displaced_step_copy_insn_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,
- arm_displaced_step_closure *dsc)
+ arm_displaced_step_copy_insn_closure *dsc)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
dsc->wrote_to_pc = 1;
/* Preparation: tmp[0] <- r14
- r14 <- <scratch space>+4
+ r14 <- <scratch space>+4
*(<scratch space>+8) <- from
Insn: ldr pc, [r14, #4]
Cleanup: r14 <- tmp[0], pc <- tmp[0]. */
the program has stepped into a Linux kernel helper routine (which must be
handled as a special case). */
-static struct displaced_step_closure *
+static displaced_step_copy_insn_closure_up
arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
- arm_displaced_step_closure *dsc = new arm_displaced_step_closure;
+ std::unique_ptr<arm_displaced_step_copy_insn_closure> dsc
+ (new arm_displaced_step_copy_insn_closure);
/* Detect when we enter an (inaccessible by GDB) Linux kernel helper, and
stop at the return location. */
if (from > 0xffff0000)
{
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: detected kernel helper "
- "at %.8lx\n", (unsigned long) from);
+ displaced_debug_printf ("detected kernel helper at %.8lx",
+ (unsigned long) from);
- arm_catch_kernel_helper_return (gdbarch, from, to, regs, dsc);
+ arm_catch_kernel_helper_return (gdbarch, from, to, regs, dsc.get ());
}
else
{
/* Override the default handling of SVC instructions. */
dsc->u.svc.copy_svc_os = arm_linux_copy_svc;
- arm_process_displaced_insn (gdbarch, from, to, regs, dsc);
+ arm_process_displaced_insn (gdbarch, from, to, regs, dsc.get ());
}
- arm_displaced_init_closure (gdbarch, from, to, dsc);
+ arm_displaced_init_closure (gdbarch, from, to, dsc.get ());
- return dsc;
+ /* This is a work around for a problem with g++ 4.8. */
+ return displaced_step_copy_insn_closure_up (dsc.release ());
}
/* Implementation of `gdbarch_stap_is_single_operand', as defined in
It returns one if the special token has been parsed successfully,
or zero if the current token is not considered special. */
-static int
+static expr::operation_up
arm_stap_parse_special_token (struct gdbarch *gdbarch,
struct stap_parse_info *p)
{
int len, offset;
int got_minus = 0;
long displacement;
- struct stoken str;
++tmp;
start = tmp;
++tmp;
if (*tmp != ',')
- return 0;
+ return {};
len = tmp - start;
regname = (char *) alloca (len + 2);
/* Skipping last `]'. */
if (*tmp++ != ']')
- return 0;
+ return {};
+ p->arg = tmp;
+
+ using namespace expr;
/* The displacement. */
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (&p->pstate, displacement);
- write_exp_elt_opcode (&p->pstate, OP_LONG);
+ struct type *long_type = builtin_type (gdbarch)->builtin_long;
if (got_minus)
- write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+ displacement = -displacement;
+ operation_up disp = make_operation<long_const_operation> (long_type,
+ displacement);
/* The register name. */
- write_exp_elt_opcode (&p->pstate, OP_REGISTER);
- str.ptr = regname;
- str.length = len;
- write_exp_string (&p->pstate, str);
- write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+ operation_up reg
+ = make_operation<register_operation> (regname);
- write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+ operation_up sum
+ = make_operation<add_operation> (std::move (reg), std::move (disp));
/* Casting to the expected type. */
- write_exp_elt_opcode (&p->pstate, UNOP_CAST);
- write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
- write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
- write_exp_elt_opcode (&p->pstate, UNOP_IND);
-
- p->arg = tmp;
+ struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+ sum = make_operation<unop_cast_operation> (std::move (sum),
+ arg_ptr_type);
+ return make_operation<unop_ind_operation> (std::move (sum));
}
- else
- return 0;
- return 1;
+ return {};
}
/* ARM process record-replay constructs: syscall, signal etc. */
-struct linux_record_tdep arm_linux_record_tdep;
+static linux_record_tdep arm_linux_record_tdep;
/* arm_canonicalize_syscall maps from the native arm Linux set
of syscall ids into a canonical set of syscall ids used by
for (i = 0; i < ARM_PC_REGNUM; i++)
{
if (record_full_arch_list_add_reg (regcache, ARM_A1_REGNUM + i))
- return -1;
+ return -1;
}
if (record_full_arch_list_add_reg (regcache, ARM_PS_REGNUM))
if (syscall_gdb == gdb_sys_no_syscall)
{
printf_unfiltered (_("Process record and replay target doesn't "
- "support syscall number %s\n"),
- plongest (svc_number));
+ "support syscall number %s\n"),
+ plongest (svc_number));
return -1;
}
}
ret = record_linux_system_call (syscall_gdb, regcache,
- &arm_linux_record_tdep);
+ &arm_linux_record_tdep);
if (ret != 0)
return ret;
/* Implement the gcc_target_options gdbarch method. */
-static char *
+static std::string
arm_linux_gcc_target_options (struct gdbarch *gdbarch)
{
/* GCC doesn't know "-m32". */
- return NULL;
+ return {};
}
static void
NULL };
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- linux_init_abi (info, gdbarch);
+ linux_init_abi (info, gdbarch, 1);
tdep->lowest_pc = 0x8000;
if (info.byte_order_for_code == BFD_ENDIAN_BIG)
default:
internal_error
(__FILE__, __LINE__,
- _("arm_linux_init_abi: Floating point model not supported"));
+ _("arm_linux_init_abi: Floating point model not supported"));
break;
}
tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
- svr4_fetch_objfile_link_map);
+ svr4_fetch_objfile_link_map);
tramp_frame_prepend_unwinder (gdbarch,
&arm_linux_sigreturn_tramp_frame);
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_location (gdbarch, linux_displaced_step_location);
/* Reversible debugging, process record. */
set_gdbarch_process_record (gdbarch, arm_process_record);
set_gdbarch_gcc_target_options (gdbarch, arm_linux_gcc_target_options);
}
+void _initialize_arm_linux_tdep ();
void
-_initialize_arm_linux_tdep (void)
+_initialize_arm_linux_tdep ()
{
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX,
arm_linux_init_abi);