/* Common target dependent code for GDB on AArch64 systems.
- Copyright (C) 2009-2019 Free Software Foundation, Inc.
+ Copyright (C) 2009-2020 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of GDB.
#include "defs.h"
#include "frame.h"
-#include "inferior.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "dis-asm.h"
#include "trad-frame.h"
#include "objfiles.h"
#include "dwarf2.h"
-#include "dwarf2-frame.h"
+#include "dwarf2/frame.h"
#include "gdbtypes.h"
#include "prologue-value.h"
#include "target-descriptions.h"
#include "user-regs.h"
-#include "language.h"
-#include "infcall.h"
-#include "ax.h"
#include "ax-gdb.h"
#include "gdbsupport/selftest.h"
#include "aarch64-tdep.h"
#include "aarch64-ravenscar-thread.h"
-#include "elf-bfd.h"
-#include "elf/aarch64.h"
-
#include "record.h"
#include "record-full.h"
#include "arch/aarch64-insn.h"
return false;
}
+/* Used for matching BRK instructions for AArch64. */
+static constexpr uint32_t BRK_INSN_MASK = 0xffe0001f;
+static constexpr uint32_t BRK_INSN_BASE = 0xd4200000;
+
+/* Implementation of gdbarch_program_breakpoint_here_p for aarch64. */
+
+static bool
+aarch64_program_breakpoint_here_p (gdbarch *gdbarch, CORE_ADDR address)
+{
+ const uint32_t insn_len = 4;
+ gdb_byte target_mem[4];
+
+ /* Enable the automatic memory restoration from breakpoints while
+ we read the memory. Otherwise we may find temporary breakpoints, ones
+ inserted by GDB, and flag them as permanent breakpoints. */
+ scoped_restore restore_memory
+ = make_scoped_restore_show_memory_breakpoints (0);
+
+ if (target_read_memory (address, target_mem, insn_len) == 0)
+ {
+ uint32_t insn =
+ (uint32_t) extract_unsigned_integer (target_mem, insn_len,
+ gdbarch_byte_order_for_code (gdbarch));
+
+ /* Check if INSN is a BRK instruction pattern. There are multiple choices
+ of such instructions with different immediate values. Different OS'
+ may use a different variation, but they have the same outcome. */
+ return ((insn & BRK_INSN_MASK) == BRK_INSN_BASE);
+ }
+
+ return false;
+}
+
/* When arguments must be pushed onto the stack, they go on in reverse
order. The code below implements a FILO (stack) to do this. */
};
/* Pass a value in a sequence of consecutive X registers. The caller
- is responsbile for ensuring sufficient registers are available. */
+ is responsible for ensuring sufficient registers are available. */
static void
pass_in_x (struct gdbarch *gdbarch, struct regcache *regcache,
if (tdep->vnv_type == NULL)
{
- /* The other AArch64 psuedo registers (Q,D,H,S,B) refer to a single value
+ /* The other AArch64 pseudo registers (Q,D,H,S,B) refer to a single value
slice from the non-pseudo vector registers. However NEON V registers
are always vector registers, and need constructing as such. */
const struct builtin_type *bt = builtin_type (gdbarch);
{
/* It is true when condition instruction, such as B.CON, TBZ, etc,
is being displaced stepping. */
- int cond = 0;
+ bool cond = false;
- /* PC adjustment offset after displaced stepping. */
+ /* PC adjustment offset after displaced stepping. If 0, then we don't
+ write the PC back, assuming the PC is already the right address. */
int32_t pc_adjust = 0;
};
*/
emit_bcond (dsd->insn_buf, cond, 8);
- dsd->dsc->cond = 1;
+ dsd->dsc->cond = true;
dsd->dsc->pc_adjust = offset;
dsd->insn_count = 1;
}
*/
emit_cb (dsd->insn_buf, is_cbnz, aarch64_register (rn, is64), 8);
dsd->insn_count = 1;
- dsd->dsc->cond = 1;
+ dsd->dsc->cond = true;
dsd->dsc->pc_adjust = offset;
}
*/
emit_tb (dsd->insn_buf, is_tbnz, bit, aarch64_register (rt, 1), 8);
dsd->insn_count = 1;
- dsd->dsc->cond = 1;
+ dsd->dsc->cond = true;
dsd->dsc->pc_adjust = offset;
}
/* Implement the "displaced_step_copy_insn" gdbarch method. */
-struct displaced_step_closure *
+displaced_step_closure_up
aarch64_displaced_step_copy_insn (struct gdbarch *gdbarch,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
dsc = NULL;
}
- return dsc.release ();
+ /* This is a work around for a problem with g++ 4.8. */
+ return displaced_step_closure_up (dsc.release ());
}
/* Implement the "displaced_step_fixup" gdbarch method. */
{
aarch64_displaced_step_closure *dsc = (aarch64_displaced_step_closure *) dsc_;
+ ULONGEST pc;
+
+ regcache_cooked_read_unsigned (regs, AARCH64_PC_REGNUM, &pc);
+
+ if (debug_displaced)
+ debug_printf ("Displaced: PC after stepping: %s (was %s).\n",
+ paddress (gdbarch, pc), paddress (gdbarch, to));
+
if (dsc->cond)
{
- ULONGEST pc;
+ if (debug_displaced)
+ debug_printf ("Displaced: [Conditional] pc_adjust before: %d\n",
+ dsc->pc_adjust);
- regcache_cooked_read_unsigned (regs, AARCH64_PC_REGNUM, &pc);
if (pc - to == 8)
{
/* Condition is true. */
}
else
gdb_assert_not_reached ("Unexpected PC value after displaced stepping");
+
+ if (debug_displaced)
+ debug_printf ("Displaced: [Conditional] pc_adjust after: %d\n",
+ dsc->pc_adjust);
}
+ if (debug_displaced)
+ debug_printf ("Displaced: %s PC by %d\n",
+ dsc->pc_adjust? "adjusting" : "not adjusting",
+ dsc->pc_adjust);
+
+
if (dsc->pc_adjust != 0)
{
+ /* Make sure the previous instruction was executed (that is, the PC
+ has changed). If the PC didn't change, then discard the adjustment
+ offset. Otherwise we may skip an instruction before its execution
+ took place. */
+ if ((pc - to) == 0)
+ {
+ if (debug_displaced)
+ debug_printf ("Displaced: PC did not move. Discarding PC "
+ "adjustment.\n");
+ dsc->pc_adjust = 0;
+ }
+
if (debug_displaced)
{
- debug_printf ("displaced: fixup: set PC to %s:%d\n",
+ debug_printf ("Displaced: fixup: set PC to %s:%d\n",
paddress (gdbarch, from), dsc->pc_adjust);
}
regcache_cooked_write_unsigned (regs, AARCH64_PC_REGNUM,
set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch,
aarch64_execute_dwarf_cfa_vendor_op);
+ /* Permanent/Program breakpoint handling. */
+ set_gdbarch_program_breakpoint_here_p (gdbarch,
+ aarch64_program_breakpoint_here_p);
+
/* Add some default predicates. */
frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);
dwarf2_append_unwinders (gdbarch);
}
#endif
+void _initialize_aarch64_tdep ();
void
-_initialize_aarch64_tdep (void)
+_initialize_aarch64_tdep ()
{
gdbarch_register (bfd_arch_aarch64, aarch64_gdbarch_init,
aarch64_dump_tdep);