/* Common target dependent code for GDB on AArch64 systems.
- Copyright (C) 2009-2018 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 "frame-base.h"
#include "trad-frame.h"
#include "objfiles.h"
-#include "dwarf2-frame.h"
+#include "dwarf2.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 "selftest.h"
+#include "gdbsupport/selftest.h"
#include "aarch64-tdep.h"
-
-#include "elf-bfd.h"
-#include "elf/aarch64.h"
-
-#include "vec.h"
+#include "aarch64-ravenscar-thread.h"
#include "record.h"
#include "record-full.h"
#include "arch/aarch64-insn.h"
+#include "gdbarch.h"
#include "opcode/aarch64.h"
#include <algorithm>
#define bit(obj,st) (((obj) >> (st)) & 1)
#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
-/* Pseudo register base numbers. */
-#define AARCH64_Q0_REGNUM 0
-#define AARCH64_D0_REGNUM (AARCH64_Q0_REGNUM + AARCH64_D_REGISTER_COUNT)
-#define AARCH64_S0_REGNUM (AARCH64_D0_REGNUM + 32)
-#define AARCH64_H0_REGNUM (AARCH64_S0_REGNUM + 32)
-#define AARCH64_B0_REGNUM (AARCH64_H0_REGNUM + 32)
-#define AARCH64_SVE_V0_REGNUM (AARCH64_B0_REGNUM + 32)
-
/* A Homogeneous Floating-Point or Short-Vector Aggregate may have at most
four members. */
#define HA_MAX_NUM_FLDS 4
/* All possible aarch64 target descriptors. */
-struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1];
+struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/];
/* The standard register names, and all the valid aliases for them. */
static const struct
"ffr", "vg"
};
+static const char *const aarch64_pauth_register_names[] =
+{
+ /* Authentication mask for data pointer. */
+ "pauth_dmask",
+ /* Authentication mask for code pointer. */
+ "pauth_cmask"
+};
+
/* AArch64 prologue cache structure. */
struct aarch64_prologue_cache
{
static void
show_aarch64_debug (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
+ struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("AArch64 debugging is %s.\n"), value);
}
} // namespace
+/* If address signing is enabled, mask off the signature bits from the link
+ register, which is passed by value in ADDR, using the register values in
+ THIS_FRAME. */
+
+static CORE_ADDR
+aarch64_frame_unmask_lr (struct gdbarch_tdep *tdep,
+ struct frame_info *this_frame, CORE_ADDR addr)
+{
+ if (tdep->has_pauth ()
+ && frame_unwind_register_unsigned (this_frame,
+ tdep->pauth_ra_state_regnum))
+ {
+ int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base);
+ CORE_ADDR cmask = frame_unwind_register_unsigned (this_frame, cmask_num);
+ addr = addr & ~cmask;
+
+ /* Record in the frame that the link register required unmasking. */
+ set_frame_previous_pc_masked (this_frame);
+ }
+
+ return addr;
+}
+
+/* Implement the "get_pc_address_flags" gdbarch method. */
+
+static std::string
+aarch64_get_pc_address_flags (frame_info *frame, CORE_ADDR pc)
+{
+ if (pc != 0 && get_frame_pc_masked (frame))
+ return "PAC";
+
+ return "";
+}
+
/* Analyze a prologue, looking for a recognizable stack frame
and frame pointer. Scan until we encounter a store that could
clobber the stack frame unexpectedly, or an unknown instruction. */
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
int i;
+
+ /* Whether the stack has been set. This should be true when we notice a SP
+ to FP move or if we are using the SP as the base register for storing
+ data, in case the FP is ommitted. */
+ bool seen_stack_set = false;
+
/* Track X registers and D registers in prologue. */
pv_t regs[AARCH64_X_REGISTER_COUNT + AARCH64_D_REGISTER_COUNT];
regs[rd] = pv_add_constant (regs[rn],
-inst.operands[2].imm.value);
}
+
+ /* Did we move SP to FP? */
+ if (rn == AARCH64_SP_REGNUM && rd == AARCH64_FP_REGNUM)
+ seen_stack_set = true;
}
else if (inst.opcode->iclass == pcreladdr
&& inst.operands[1].type == AARCH64_OPND_ADDR_ADRP)
else if (inst.opcode->op == OP_MOVZ)
{
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
+
+ /* If this shows up before we set the stack, keep going. Otherwise
+ stop the analysis. */
+ if (seen_stack_set)
+ break;
+
regs[inst.operands[0].reg.regno] = pv_unknown ();
}
else if (inst.opcode->iclass == log_shift
{
unsigned rt = inst.operands[0].reg.regno;
unsigned rn = inst.operands[1].addr.base_regno;
- int is64
- = (aarch64_get_qualifier_esize (inst.operands[0].qualifier) == 8);
+ int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier);
gdb_assert (aarch64_num_of_operands (inst.opcode) == 2);
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt);
gdb_assert (inst.operands[1].type == AARCH64_OPND_ADDR_SIMM9);
gdb_assert (!inst.operands[1].addr.offset.is_reg);
- stack.store (pv_add_constant (regs[rn],
- inst.operands[1].addr.offset.imm),
- is64 ? 8 : 4, regs[rt]);
+ stack.store
+ (pv_add_constant (regs[rn], inst.operands[1].addr.offset.imm),
+ size, regs[rt]);
+
+ /* Are we storing with SP as a base? */
+ if (rn == AARCH64_SP_REGNUM)
+ seen_stack_set = true;
}
else if ((inst.opcode->iclass == ldstpair_off
|| (inst.opcode->iclass == ldstpair_indexed
unsigned rt2;
unsigned rn = inst.operands[2].addr.base_regno;
int32_t imm = inst.operands[2].addr.offset.imm;
+ int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier);
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt
|| inst.operands[0].type == AARCH64_OPND_Ft);
rt2 = inst.operands[1].reg.regno;
if (inst.operands[0].type == AARCH64_OPND_Ft)
{
- /* Only bottom 64-bit of each V register (D register) need
- to be preserved. */
- gdb_assert (inst.operands[0].qualifier == AARCH64_OPND_QLF_S_D);
rt1 += AARCH64_X_REGISTER_COUNT;
rt2 += AARCH64_X_REGISTER_COUNT;
}
- stack.store (pv_add_constant (regs[rn], imm), 8,
- regs[rt1]);
- stack.store (pv_add_constant (regs[rn], imm + 8), 8,
- regs[rt2]);
+ stack.store (pv_add_constant (regs[rn], imm), size, regs[rt1]);
+ stack.store (pv_add_constant (regs[rn], imm + size), size, regs[rt2]);
if (inst.operands[2].addr.writeback)
regs[rn] = pv_add_constant (regs[rn], imm);
+ /* Ignore the instruction that allocates stack space and sets
+ the SP. */
+ if (rn == AARCH64_SP_REGNUM && !inst.operands[2].addr.writeback)
+ seen_stack_set = true;
}
else if ((inst.opcode->iclass == ldst_imm9 /* Signed immediate. */
|| (inst.opcode->iclass == ldst_pos /* Unsigned immediate. */
unsigned int rt = inst.operands[0].reg.regno;
int32_t imm = inst.operands[1].addr.offset.imm;
unsigned int rn = inst.operands[1].addr.base_regno;
- bool is64
- = (aarch64_get_qualifier_esize (inst.operands[0].qualifier) == 8);
+ int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier);
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt
|| inst.operands[0].type == AARCH64_OPND_Ft);
if (inst.operands[0].type == AARCH64_OPND_Ft)
- {
- /* Only bottom 64-bit of each V register (D register) need
- to be preserved. */
- gdb_assert (inst.operands[0].qualifier == AARCH64_OPND_QLF_S_D);
- rt += AARCH64_X_REGISTER_COUNT;
- }
+ rt += AARCH64_X_REGISTER_COUNT;
- stack.store (pv_add_constant (regs[rn], imm),
- is64 ? 8 : 4, regs[rt]);
+ stack.store (pv_add_constant (regs[rn], imm), size, regs[rt]);
if (inst.operands[1].addr.writeback)
regs[rn] = pv_add_constant (regs[rn], imm);
+
+ /* Are we storing with SP as a base? */
+ if (rn == AARCH64_SP_REGNUM)
+ seen_stack_set = true;
}
else if (inst.opcode->iclass == testbranch)
{
/* Stop analysis on branch. */
break;
}
+ else if (inst.opcode->iclass == ic_system)
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int ra_state_val = 0;
+
+ if (insn == 0xd503233f /* paciasp. */
+ || insn == 0xd503237f /* pacibsp. */)
+ {
+ /* Return addresses are mangled. */
+ ra_state_val = 1;
+ }
+ else if (insn == 0xd50323bf /* autiasp. */
+ || insn == 0xd50323ff /* autibsp. */)
+ {
+ /* Return addresses are not mangled. */
+ ra_state_val = 0;
+ }
+ else
+ {
+ if (aarch64_debug)
+ debug_printf ("aarch64: prologue analysis gave up addr=%s"
+ " opcode=0x%x (iclass)\n",
+ core_addr_to_string_nz (start), insn);
+ break;
+ }
+
+ if (tdep->has_pauth () && cache != nullptr)
+ trad_frame_set_value (cache->saved_regs,
+ tdep->pauth_ra_state_regnum,
+ ra_state_val);
+ }
else
{
if (aarch64_debug)
struct gdbarch *gdbarch = gdbarch_find_by_info (info);
SELF_CHECK (gdbarch != NULL);
+ struct aarch64_prologue_cache cache;
+ cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
/* Test the simple prologue in which frame pointer is used. */
{
- struct aarch64_prologue_cache cache;
- cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
-
static const uint32_t insns[] = {
0xa9af7bfd, /* stp x29, x30, [sp,#-272]! */
0x910003fd, /* mov x29, sp */
/* Test a prologue in which STR is used and frame pointer is not
used. */
{
- struct aarch64_prologue_cache cache;
- cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
-
static const uint32_t insns[] = {
0xf81d0ff3, /* str x19, [sp, #-48]! */
0xb9002fe0, /* str w0, [sp, #44] */
};
instruction_reader_test reader (insns);
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
SELF_CHECK (end == 4 * 5);
== -1);
}
}
+
+ /* Test handling of movz before setting the frame pointer. */
+ {
+ static const uint32_t insns[] = {
+ 0xa9bf7bfd, /* stp x29, x30, [sp, #-16]! */
+ 0x52800020, /* mov w0, #0x1 */
+ 0x910003fd, /* mov x29, sp */
+ 0x528000a2, /* mov w2, #0x5 */
+ 0x97fffff8, /* bl 6e4 */
+ };
+
+ instruction_reader_test reader (insns);
+
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+ CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
+
+ /* We should stop at the 4th instruction. */
+ SELF_CHECK (end == (4 - 1) * 4);
+ SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
+ SELF_CHECK (cache.framesize == 16);
+ }
+
+ /* Test handling of movz/stp when using the stack pointer as frame
+ pointer. */
+ {
+ static const uint32_t insns[] = {
+ 0xa9bc7bfd, /* stp x29, x30, [sp, #-64]! */
+ 0x52800020, /* mov w0, #0x1 */
+ 0x290207e0, /* stp w0, w1, [sp, #16] */
+ 0xa9018fe2, /* stp x2, x3, [sp, #24] */
+ 0x528000a2, /* mov w2, #0x5 */
+ 0x97fffff8, /* bl 6e4 */
+ };
+
+ instruction_reader_test reader (insns);
+
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+ CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
+
+ /* We should stop at the 5th instruction. */
+ SELF_CHECK (end == (5 - 1) * 4);
+ SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
+ SELF_CHECK (cache.framesize == 64);
+ }
+
+ /* Test handling of movz/str when using the stack pointer as frame
+ pointer */
+ {
+ static const uint32_t insns[] = {
+ 0xa9bc7bfd, /* stp x29, x30, [sp, #-64]! */
+ 0x52800020, /* mov w0, #0x1 */
+ 0xb9002be4, /* str w4, [sp, #40] */
+ 0xf9001be5, /* str x5, [sp, #48] */
+ 0x528000a2, /* mov w2, #0x5 */
+ 0x97fffff8, /* bl 6e4 */
+ };
+
+ instruction_reader_test reader (insns);
+
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+ CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
+
+ /* We should stop at the 5th instruction. */
+ SELF_CHECK (end == (5 - 1) * 4);
+ SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
+ SELF_CHECK (cache.framesize == 64);
+ }
+
+ /* Test handling of movz/stur when using the stack pointer as frame
+ pointer. */
+ {
+ static const uint32_t insns[] = {
+ 0xa9bc7bfd, /* stp x29, x30, [sp, #-64]! */
+ 0x52800020, /* mov w0, #0x1 */
+ 0xb80343e6, /* stur w6, [sp, #52] */
+ 0xf80383e7, /* stur x7, [sp, #56] */
+ 0x528000a2, /* mov w2, #0x5 */
+ 0x97fffff8, /* bl 6e4 */
+ };
+
+ instruction_reader_test reader (insns);
+
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+ CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
+
+ /* We should stop at the 5th instruction. */
+ SELF_CHECK (end == (5 - 1) * 4);
+ SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
+ SELF_CHECK (cache.framesize == 64);
+ }
+
+ /* Test handling of movz when there is no frame pointer set or no stack
+ pointer used. */
+ {
+ static const uint32_t insns[] = {
+ 0xa9bf7bfd, /* stp x29, x30, [sp, #-16]! */
+ 0x52800020, /* mov w0, #0x1 */
+ 0x528000a2, /* mov w2, #0x5 */
+ 0x97fffff8, /* bl 6e4 */
+ };
+
+ instruction_reader_test reader (insns);
+
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+ CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
+
+ /* We should stop at the 4th instruction. */
+ SELF_CHECK (end == (4 - 1) * 4);
+ SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
+ SELF_CHECK (cache.framesize == 16);
+ }
+
+ /* Test a prologue in which there is a return address signing instruction. */
+ if (tdep->has_pauth ())
+ {
+ static const uint32_t insns[] = {
+ 0xd503233f, /* paciasp */
+ 0xa9bd7bfd, /* stp x29, x30, [sp, #-48]! */
+ 0x910003fd, /* mov x29, sp */
+ 0xf801c3f3, /* str x19, [sp, #28] */
+ 0xb9401fa0, /* ldr x19, [x29, #28] */
+ };
+ instruction_reader_test reader (insns);
+
+ trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+ CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache,
+ reader);
+
+ SELF_CHECK (end == 4 * 4);
+ SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
+ SELF_CHECK (cache.framesize == 48);
+
+ for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
+ {
+ if (i == 19)
+ SELF_CHECK (cache.saved_regs[i].addr == -20);
+ else if (i == AARCH64_FP_REGNUM)
+ SELF_CHECK (cache.saved_regs[i].addr == -48);
+ else if (i == AARCH64_LR_REGNUM)
+ SELF_CHECK (cache.saved_regs[i].addr == -40);
+ else
+ SELF_CHECK (cache.saved_regs[i].addr == -1);
+ }
+
+ if (tdep->has_pauth ())
+ {
+ SELF_CHECK (trad_frame_value_p (cache.saved_regs,
+ tdep->pauth_ra_state_regnum));
+ SELF_CHECK (cache.saved_regs[tdep->pauth_ra_state_regnum].addr == 1);
+ }
+ }
}
} // namespace selftests
#endif /* GDB_SELF_TEST */
cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
*this_cache = cache;
- TRY
+ try
{
aarch64_make_prologue_cache_1 (this_frame, cache);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
return cache;
}
if (prev_regnum == AARCH64_PC_REGNUM)
{
CORE_ADDR lr;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
+
+ if (tdep->has_pauth ()
+ && trad_frame_value_p (cache->saved_regs,
+ tdep->pauth_ra_state_regnum))
+ lr = aarch64_frame_unmask_lr (tdep, this_frame, lr);
+
return frame_unwind_got_constant (this_frame, prev_regnum, lr);
}
identified by the next frame's stack pointer at the time of the
call. The value was already reconstructed into PREV_SP. */
/*
- +----------+ ^
- | saved lr | |
+ +----------+ ^
+ | saved lr | |
+->| saved fp |--+
| | |
| | | <- Previous SP
| +----------+
| | saved lr |
+--| saved fp |<- FP
- | |
- | |<- SP
- +----------+ */
+ | |
+ | |<- SP
+ +----------+ */
if (prev_regnum == AARCH64_SP_REGNUM)
return frame_unwind_got_constant (this_frame, prev_regnum,
cache->prev_sp);
cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
*this_cache = cache;
- TRY
+ try
{
cache->prev_sp = get_frame_register_unsigned (this_frame,
AARCH64_SP_REGNUM);
cache->prev_pc = get_frame_pc (this_frame);
cache->available_p = 1;
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
return cache;
}
aarch64_normal_frame_base
};
-/* Assuming THIS_FRAME is a dummy, return the frame ID of that
- dummy frame. The frame ID's base needs to match the TOS value
- saved by save_dummy_frame_tos () and returned from
- aarch64_push_dummy_call, and the PC needs to match the dummy
- frame's breakpoint. */
-
-static struct frame_id
-aarch64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
-{
- return frame_id_build (get_frame_register_unsigned (this_frame,
- AARCH64_SP_REGNUM),
- get_frame_pc (this_frame));
-}
-
-/* Implement the "unwind_pc" gdbarch method. */
-
-static CORE_ADDR
-aarch64_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
-{
- CORE_ADDR pc
- = frame_unwind_register_unsigned (this_frame, AARCH64_PC_REGNUM);
-
- return pc;
-}
-
-/* Implement the "unwind_sp" gdbarch method. */
-
-static CORE_ADDR
-aarch64_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
-{
- return frame_unwind_register_unsigned (this_frame, AARCH64_SP_REGNUM);
-}
-
/* Return the value of the REGNUM register in the previous frame of
*THIS_FRAME. */
aarch64_dwarf2_prev_register (struct frame_info *this_frame,
void **this_cache, int regnum)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
CORE_ADDR lr;
switch (regnum)
{
case AARCH64_PC_REGNUM:
lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
+ lr = aarch64_frame_unmask_lr (tdep, this_frame, lr);
return frame_unwind_got_constant (this_frame, regnum, lr);
default:
}
}
+static const unsigned char op_lit0 = DW_OP_lit0;
+static const unsigned char op_lit1 = DW_OP_lit1;
+
/* Implement the "init_reg" dwarf2_frame_ops method. */
static void
struct dwarf2_frame_state_reg *reg,
struct frame_info *this_frame)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
switch (regnum)
{
case AARCH64_PC_REGNUM:
reg->how = DWARF2_FRAME_REG_FN;
reg->loc.fn = aarch64_dwarf2_prev_register;
- break;
+ return;
+
case AARCH64_SP_REGNUM:
reg->how = DWARF2_FRAME_REG_CFA;
- break;
+ return;
}
-}
-
-/* When arguments must be pushed onto the stack, they go on in reverse
- order. The code below implements a FILO (stack) to do this. */
-typedef struct
-{
- /* Value to pass on stack. It can be NULL if this item is for stack
- padding. */
- const gdb_byte *data;
-
- /* Size in bytes of value to pass on stack. */
- int len;
-} stack_item_t;
-
-DEF_VEC_O (stack_item_t);
+ /* Init pauth registers. */
+ if (tdep->has_pauth ())
+ {
+ if (regnum == tdep->pauth_ra_state_regnum)
+ {
+ /* Initialize RA_STATE to zero. */
+ reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
+ reg->loc.exp.start = &op_lit0;
+ reg->loc.exp.len = 1;
+ return;
+ }
+ else if (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
+ || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
+ {
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+ return;
+ }
+ }
+}
-/* Return the alignment (in bytes) of the given type. */
+/* Implement the execute_dwarf_cfa_vendor_op method. */
-static int
-aarch64_type_align (struct type *t)
+static bool
+aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
+ struct dwarf2_frame_state *fs)
{
- int n;
- int align;
- int falign;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct dwarf2_frame_state_reg *ra_state;
- t = check_typedef (t);
- switch (TYPE_CODE (t))
+ if (op == DW_CFA_AARCH64_negate_ra_state)
{
- default:
- /* Should never happen. */
- internal_error (__FILE__, __LINE__, _("unknown type alignment"));
- return 4;
+ /* On systems without pauth, treat as a nop. */
+ if (!tdep->has_pauth ())
+ return true;
- case TYPE_CODE_PTR:
- case TYPE_CODE_ENUM:
- case TYPE_CODE_INT:
- case TYPE_CODE_FLT:
- case TYPE_CODE_SET:
- case TYPE_CODE_RANGE:
- case TYPE_CODE_BITSTRING:
- case TYPE_CODE_REF:
- case TYPE_CODE_RVALUE_REF:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_BOOL:
- return TYPE_LENGTH (t);
+ /* Allocate RA_STATE column if it's not allocated yet. */
+ fs->regs.alloc_regs (AARCH64_DWARF_PAUTH_RA_STATE + 1);
- case TYPE_CODE_ARRAY:
- if (TYPE_VECTOR (t))
- {
- /* Use the natural alignment for vector types (the same for
- scalar type), but the maximum alignment is 128-bit. */
- if (TYPE_LENGTH (t) > 16)
- return 16;
- else
- return TYPE_LENGTH (t);
- }
+ /* Toggle the status of RA_STATE between 0 and 1. */
+ ra_state = &(fs->regs.reg[AARCH64_DWARF_PAUTH_RA_STATE]);
+ ra_state->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
+
+ if (ra_state->loc.exp.start == nullptr
+ || ra_state->loc.exp.start == &op_lit0)
+ ra_state->loc.exp.start = &op_lit1;
else
- return aarch64_type_align (TYPE_TARGET_TYPE (t));
- case TYPE_CODE_COMPLEX:
- return aarch64_type_align (TYPE_TARGET_TYPE (t));
+ ra_state->loc.exp.start = &op_lit0;
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- align = 1;
- for (n = 0; n < TYPE_NFIELDS (t); n++)
- {
- falign = aarch64_type_align (TYPE_FIELD_TYPE (t, n));
- if (falign > align)
- align = falign;
- }
- return align;
+ ra_state->loc.exp.len = 1;
+
+ return true;
}
+
+ return false;
}
-/* Return 1 if *TY is a homogeneous floating-point aggregate or
- homogeneous short-vector aggregate as defined in the AAPCS64 ABI
- document; otherwise return 0. */
+/* Used for matching BRK instructions for AArch64. */
+static constexpr uint32_t BRK_INSN_MASK = 0xffe0001f;
+static constexpr uint32_t BRK_INSN_BASE = 0xd4200000;
-static int
-is_hfa_or_hva (struct type *ty)
+/* Implementation of gdbarch_program_breakpoint_here_p for aarch64. */
+
+static bool
+aarch64_program_breakpoint_here_p (gdbarch *gdbarch, CORE_ADDR address)
{
- switch (TYPE_CODE (ty))
- {
- case TYPE_CODE_ARRAY:
- {
- struct type *target_ty = TYPE_TARGET_TYPE (ty);
+ const uint32_t insn_len = 4;
+ gdb_byte target_mem[4];
- if (TYPE_VECTOR (ty))
- return 0;
+ /* 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 (TYPE_LENGTH (ty) <= 4 /* HFA or HVA has at most 4 members. */
- && (TYPE_CODE (target_ty) == TYPE_CODE_FLT /* HFA */
- || (TYPE_CODE (target_ty) == TYPE_CODE_ARRAY /* HVA */
- && TYPE_VECTOR (target_ty))))
- return 1;
- break;
- }
+ 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);
+ }
- case TYPE_CODE_UNION:
- case TYPE_CODE_STRUCT:
- {
- /* HFA or HVA has at most four members. */
- if (TYPE_NFIELDS (ty) > 0 && TYPE_NFIELDS (ty) <= 4)
- {
- struct type *member0_type;
+ return false;
+}
- member0_type = check_typedef (TYPE_FIELD_TYPE (ty, 0));
- if (TYPE_CODE (member0_type) == TYPE_CODE_FLT
- || (TYPE_CODE (member0_type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (member0_type)))
- {
- int i;
+/* When arguments must be pushed onto the stack, they go on in reverse
+ order. The code below implements a FILO (stack) to do this. */
- for (i = 0; i < TYPE_NFIELDS (ty); i++)
- {
- struct type *member1_type;
+struct stack_item_t
+{
+ /* Value to pass on stack. It can be NULL if this item is for stack
+ padding. */
+ const gdb_byte *data;
- member1_type = check_typedef (TYPE_FIELD_TYPE (ty, i));
- if (TYPE_CODE (member0_type) != TYPE_CODE (member1_type)
- || (TYPE_LENGTH (member0_type)
- != TYPE_LENGTH (member1_type)))
- return 0;
- }
- return 1;
- }
- }
- return 0;
- }
+ /* Size in bytes of value to pass on stack. */
+ int len;
+};
- default:
- break;
+/* Implement the gdbarch type alignment method, overrides the generic
+ alignment algorithm for anything that is aarch64 specific. */
+
+static ULONGEST
+aarch64_type_align (gdbarch *gdbarch, struct type *t)
+{
+ t = check_typedef (t);
+ if (t->code () == TYPE_CODE_ARRAY && t->is_vector ())
+ {
+ /* Use the natural alignment for vector types (the same for
+ scalar type), but the maximum alignment is 128-bit. */
+ if (TYPE_LENGTH (t) > 16)
+ return 16;
+ else
+ return TYPE_LENGTH (t);
}
+ /* Allow the common code to calculate the alignment. */
return 0;
}
if (type == nullptr)
return -1;
- switch (TYPE_CODE (type))
+ switch (type->code ())
{
case TYPE_CODE_FLT:
if (TYPE_LENGTH (type) > 16)
if (*fundamental_type == nullptr)
*fundamental_type = type;
else if (TYPE_LENGTH (type) != TYPE_LENGTH (*fundamental_type)
- || TYPE_CODE (type) != TYPE_CODE (*fundamental_type))
+ || type->code () != (*fundamental_type)->code ())
return -1;
return 1;
if (*fundamental_type == nullptr)
*fundamental_type = target_type;
else if (TYPE_LENGTH (target_type) != TYPE_LENGTH (*fundamental_type)
- || TYPE_CODE (target_type) != TYPE_CODE (*fundamental_type))
+ || target_type->code () != (*fundamental_type)->code ())
return -1;
return 2;
case TYPE_CODE_ARRAY:
{
- if (TYPE_VECTOR (type))
+ if (type->is_vector ())
{
if (TYPE_LENGTH (type) != 8 && TYPE_LENGTH (type) != 16)
return -1;
if (*fundamental_type == nullptr)
*fundamental_type = type;
else if (TYPE_LENGTH (type) != TYPE_LENGTH (*fundamental_type)
- || TYPE_CODE (type) != TYPE_CODE (*fundamental_type))
+ || type->code () != (*fundamental_type)->code ())
return -1;
return 1;
if (count == -1)
return count;
- count *= TYPE_LENGTH (type);
+ count *= (TYPE_LENGTH (type) / TYPE_LENGTH (target_type));
return count;
}
}
{
int count = 0;
- for (int i = 0; i < TYPE_NFIELDS (type); i++)
+ for (int i = 0; i < type->num_fields (); i++)
{
- struct type *member = check_typedef (TYPE_FIELD_TYPE (type, i));
+ /* Ignore any static fields. */
+ if (field_is_static (&type->field (i)))
+ continue;
+
+ struct type *member = check_typedef (type->field (i).type ());
int sub_count = aapcs_is_vfp_call_or_return_candidate_1
(member, fundamental_type);
return -1;
count += sub_count;
}
+
+ /* Ensure there is no padding between the fields (allowing for empty
+ zero length structs) */
+ int ftype_length = (*fundamental_type == nullptr)
+ ? 0 : TYPE_LENGTH (*fundamental_type);
+ if (count * ftype_length != TYPE_LENGTH (type))
+ return -1;
+
return count;
}
Note that HFAs and HVAs can include nested structures and arrays. */
-bool
+static bool
aapcs_is_vfp_call_or_return_candidate (struct type *type, int *count,
struct type **fundamental_type)
{
struct aarch64_call_info
{
/* the current argument number. */
- unsigned argnum;
+ unsigned argnum = 0;
/* The next general purpose register number, equivalent to NGRN as
described in the AArch64 Procedure Call Standard. */
- unsigned ngrn;
+ unsigned ngrn = 0;
/* The next SIMD and floating point register number, equivalent to
NSRN as described in the AArch64 Procedure Call Standard. */
- unsigned nsrn;
+ unsigned nsrn = 0;
/* The next stacked argument address, equivalent to NSAA as
described in the AArch64 Procedure Call Standard. */
- unsigned nsaa;
+ unsigned nsaa = 0;
/* Stack item vector. */
- VEC(stack_item_t) *si;
+ std::vector<stack_item_t> si;
};
/* 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,
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int len = TYPE_LENGTH (type);
- enum type_code typecode = TYPE_CODE (type);
+ enum type_code typecode = type->code ();
int regnum = AARCH64_X0_REGNUM + info->ngrn;
const bfd_byte *buf = value_contents (arg);
if (info->nsrn < 8)
{
int regnum = AARCH64_V0_REGNUM + info->nsrn;
- gdb_byte reg[V_REGISTER_SIZE];
+ /* Enough space for a full vector register. */
+ gdb_byte reg[register_size (gdbarch, regnum)];
+ gdb_assert (len <= sizeof (reg));
info->argnum++;
info->nsrn++;
info->argnum++;
- align = aarch64_type_align (type);
+ align = type_align (type);
/* PCS C.17 Stack should be aligned to the larger of 8 bytes or the
Natural alignment of the argument's type. */
item.len = len;
item.data = buf;
- VEC_safe_push (stack_item_t, info->si, &item);
+ info->si.push_back (item);
info->nsaa += len;
if (info->nsaa & (align - 1))
item.len = pad;
item.data = NULL;
- VEC_safe_push (stack_item_t, info->si, &item);
+ info->si.push_back (item);
info->nsaa += pad;
}
}
}
}
-/* Pass a value in a V register, or on the stack if insufficient are
- available. */
-
-static void
-pass_in_v_or_stack (struct gdbarch *gdbarch,
- struct regcache *regcache,
- struct aarch64_call_info *info,
- struct type *type,
- struct value *arg)
+/* Pass a value, which is of type arg_type, in a V register. Assumes value is a
+ aapcs_is_vfp_call_or_return_candidate and there are enough spare V
+ registers. A return value of false is an error state as the value will have
+ been partially passed to the stack. */
+static bool
+pass_in_v_vfp_candidate (struct gdbarch *gdbarch, struct regcache *regcache,
+ struct aarch64_call_info *info, struct type *arg_type,
+ struct value *arg)
{
- if (!pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (type),
- value_contents (arg)))
- pass_on_stack (info, type, arg);
+ switch (arg_type->code ())
+ {
+ case TYPE_CODE_FLT:
+ return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (arg_type),
+ value_contents (arg));
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ {
+ const bfd_byte *buf = value_contents (arg);
+ struct type *target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
+
+ if (!pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (target_type),
+ buf))
+ return false;
+
+ return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (target_type),
+ buf + TYPE_LENGTH (target_type));
+ }
+
+ case TYPE_CODE_ARRAY:
+ if (arg_type->is_vector ())
+ return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (arg_type),
+ value_contents (arg));
+ /* fall through. */
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ for (int i = 0; i < arg_type->num_fields (); i++)
+ {
+ /* Don't include static fields. */
+ if (field_is_static (&arg_type->field (i)))
+ continue;
+
+ struct value *field = value_primitive_field (arg, 0, i, arg_type);
+ struct type *field_type = check_typedef (value_type (field));
+
+ if (!pass_in_v_vfp_candidate (gdbarch, regcache, info, field_type,
+ field))
+ return false;
+ }
+ return true;
+
+ default:
+ return false;
+ }
}
/* Implement the "push_dummy_call" gdbarch method. */
aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs,
- struct value **args, CORE_ADDR sp, int struct_return,
+ struct value **args, CORE_ADDR sp,
+ function_call_return_method return_method,
CORE_ADDR struct_addr)
{
int argnum;
struct aarch64_call_info info;
- struct type *func_type;
- struct type *return_type;
- int lang_struct_return;
-
- memset (&info, 0, sizeof (info));
/* We need to know what the type of the called function is in order
to determine the number of named/anonymous arguments for the
If the language code decides to pass in memory we want to move
the pointer inserted as the initial argument from the argument
list and into X8, the conventional AArch64 struct return pointer
- register.
-
- This is slightly awkward, ideally the flag "lang_struct_return"
- would be passed to the targets implementation of push_dummy_call.
- Rather that change the target interface we call the language code
- directly ourselves. */
-
- func_type = check_typedef (value_type (function));
-
- /* Dereference function pointer types. */
- if (TYPE_CODE (func_type) == TYPE_CODE_PTR)
- func_type = TYPE_TARGET_TYPE (func_type);
-
- gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
- || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
-
- /* If language_pass_by_reference () returned true we will have been
- given an additional initial argument, a hidden pointer to the
- return slot in memory. */
- return_type = TYPE_TARGET_TYPE (func_type);
- lang_struct_return = language_pass_by_reference (return_type);
+ register. */
/* Set the return address. For the AArch64, the return breakpoint
is always at BP_ADDR. */
regcache_cooked_write_unsigned (regcache, AARCH64_LR_REGNUM, bp_addr);
- /* If we were given an initial argument for the return slot because
- lang_struct_return was true, lose it. */
- if (lang_struct_return)
+ /* If we were given an initial argument for the return slot, lose it. */
+ if (return_method == return_method_hidden_param)
{
args++;
nargs--;
}
/* The struct_return pointer occupies X8. */
- if (struct_return || lang_struct_return)
+ if (return_method != return_method_normal)
{
if (aarch64_debug)
{
for (argnum = 0; argnum < nargs; argnum++)
{
struct value *arg = args[argnum];
- struct type *arg_type;
- int len;
+ struct type *arg_type, *fundamental_type;
+ int len, elements;
arg_type = check_typedef (value_type (arg));
len = TYPE_LENGTH (arg_type);
- switch (TYPE_CODE (arg_type))
+ /* If arg can be passed in v registers as per the AAPCS64, then do so if
+ if there are enough spare registers. */
+ if (aapcs_is_vfp_call_or_return_candidate (arg_type, &elements,
+ &fundamental_type))
+ {
+ if (info.nsrn + elements <= 8)
+ {
+ /* We know that we have sufficient registers available therefore
+ this will never need to fallback to the stack. */
+ if (!pass_in_v_vfp_candidate (gdbarch, regcache, &info, arg_type,
+ arg))
+ gdb_assert_not_reached ("Failed to push args");
+ }
+ else
+ {
+ info.nsrn = 8;
+ pass_on_stack (&info, arg_type, arg);
+ }
+ continue;
+ }
+
+ switch (arg_type->code ())
{
case TYPE_CODE_INT:
case TYPE_CODE_BOOL:
if (len < 4)
{
/* Promote to 32 bit integer. */
- if (TYPE_UNSIGNED (arg_type))
+ if (arg_type->is_unsigned ())
arg_type = builtin_type (gdbarch)->builtin_uint32;
else
arg_type = builtin_type (gdbarch)->builtin_int32;
pass_in_x_or_stack (gdbarch, regcache, &info, arg_type, arg);
break;
- case TYPE_CODE_COMPLEX:
- if (info.nsrn <= 6)
- {
- const bfd_byte *buf = value_contents (arg);
- struct type *target_type =
- check_typedef (TYPE_TARGET_TYPE (arg_type));
-
- pass_in_v (gdbarch, regcache, &info,
- TYPE_LENGTH (target_type), buf);
- pass_in_v (gdbarch, regcache, &info,
- TYPE_LENGTH (target_type),
- buf + TYPE_LENGTH (target_type));
- }
- else
- {
- info.nsrn = 8;
- pass_on_stack (&info, arg_type, arg);
- }
- break;
- case TYPE_CODE_FLT:
- pass_in_v_or_stack (gdbarch, regcache, &info, arg_type, arg);
- break;
-
case TYPE_CODE_STRUCT:
case TYPE_CODE_ARRAY:
case TYPE_CODE_UNION:
- if (is_hfa_or_hva (arg_type))
- {
- int elements = TYPE_NFIELDS (arg_type);
-
- /* Homogeneous Aggregates */
- if (info.nsrn + elements < 8)
- {
- int i;
-
- for (i = 0; i < elements; i++)
- {
- /* We know that we have sufficient registers
- available therefore this will never fallback
- to the stack. */
- struct value *field =
- value_primitive_field (arg, 0, i, arg_type);
- struct type *field_type =
- check_typedef (value_type (field));
-
- pass_in_v_or_stack (gdbarch, regcache, &info,
- field_type, field);
- }
- }
- else
- {
- info.nsrn = 8;
- pass_on_stack (&info, arg_type, arg);
- }
- }
- else if (TYPE_CODE (arg_type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (arg_type) && (len == 16 || len == 8))
- {
- /* Short vector types are passed in V registers. */
- pass_in_v_or_stack (gdbarch, regcache, &info, arg_type, arg);
- }
- else if (len > 16)
+ if (len > 16)
{
/* PCS B.7 Aggregates larger than 16 bytes are passed by
invisible reference. */
if (info.nsaa & 15)
sp -= 16 - (info.nsaa & 15);
- while (!VEC_empty (stack_item_t, info.si))
+ while (!info.si.empty ())
{
- stack_item_t *si = VEC_last (stack_item_t, info.si);
+ const stack_item_t &si = info.si.back ();
- sp -= si->len;
- if (si->data != NULL)
- write_memory (sp, si->data, si->len);
- VEC_pop (stack_item_t, info.si);
+ sp -= si.len;
+ if (si.data != NULL)
+ write_memory (sp, si.data, si.len);
+ info.si.pop_back ();
}
- VEC_free (stack_item_t, info.si);
-
/* Finally, update the SP register. */
regcache_cooked_write_unsigned (regcache, AARCH64_SP_REGNUM, sp);
t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnh",
TYPE_CODE_UNION);
+ elem = builtin_type (gdbarch)->builtin_half;
+ append_composite_type_field (t, "f", elem);
+
elem = builtin_type (gdbarch)->builtin_uint16;
append_composite_type_field (t, "u", elem);
if (tdep->vnv_type == NULL)
{
+ /* 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);
+
struct type *t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnv",
TYPE_CODE_UNION);
- append_composite_type_field (t, "d", aarch64_vnd_type (gdbarch));
- append_composite_type_field (t, "s", aarch64_vns_type (gdbarch));
- append_composite_type_field (t, "h", aarch64_vnh_type (gdbarch));
- append_composite_type_field (t, "b", aarch64_vnb_type (gdbarch));
- append_composite_type_field (t, "q", aarch64_vnq_type (gdbarch));
+ struct type *sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnd",
+ TYPE_CODE_UNION);
+ append_composite_type_field (sub, "f",
+ init_vector_type (bt->builtin_double, 2));
+ append_composite_type_field (sub, "u",
+ init_vector_type (bt->builtin_uint64, 2));
+ append_composite_type_field (sub, "s",
+ init_vector_type (bt->builtin_int64, 2));
+ append_composite_type_field (t, "d", sub);
+
+ sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vns",
+ TYPE_CODE_UNION);
+ append_composite_type_field (sub, "f",
+ init_vector_type (bt->builtin_float, 4));
+ append_composite_type_field (sub, "u",
+ init_vector_type (bt->builtin_uint32, 4));
+ append_composite_type_field (sub, "s",
+ init_vector_type (bt->builtin_int32, 4));
+ append_composite_type_field (t, "s", sub);
+
+ sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnh",
+ TYPE_CODE_UNION);
+ append_composite_type_field (sub, "f",
+ init_vector_type (bt->builtin_half, 8));
+ append_composite_type_field (sub, "u",
+ init_vector_type (bt->builtin_uint16, 8));
+ append_composite_type_field (sub, "s",
+ init_vector_type (bt->builtin_int16, 8));
+ append_composite_type_field (t, "h", sub);
+
+ sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnb",
+ TYPE_CODE_UNION);
+ append_composite_type_field (sub, "u",
+ init_vector_type (bt->builtin_uint8, 16));
+ append_composite_type_field (sub, "s",
+ init_vector_type (bt->builtin_int8, 16));
+ append_composite_type_field (t, "b", sub);
+
+ sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnq",
+ TYPE_CODE_UNION);
+ append_composite_type_field (sub, "u",
+ init_vector_type (bt->builtin_uint128, 1));
+ append_composite_type_field (sub, "s",
+ init_vector_type (bt->builtin_int128, 1));
+ append_composite_type_field (t, "q", sub);
tdep->vnv_type = t;
}
static int
aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
if (reg >= AARCH64_DWARF_X0 && reg <= AARCH64_DWARF_X0 + 30)
return AARCH64_X0_REGNUM + reg - AARCH64_DWARF_X0;
if (reg >= AARCH64_DWARF_SVE_P0 && reg <= AARCH64_DWARF_SVE_P0 + 15)
return AARCH64_SVE_P0_REGNUM + reg - AARCH64_DWARF_SVE_P0;
- if (reg >= AARCH64_DWARF_SVE_Z0 && reg <= AARCH64_DWARF_SVE_Z0 + 15)
- return AARCH64_SVE_Z0_REGNUM + reg - AARCH64_DWARF_SVE_Z0;
+ if (reg >= AARCH64_DWARF_SVE_Z0 && reg <= AARCH64_DWARF_SVE_Z0 + 15)
+ return AARCH64_SVE_Z0_REGNUM + reg - AARCH64_DWARF_SVE_Z0;
+
+ if (tdep->has_pauth ())
+ {
+ if (reg >= AARCH64_DWARF_PAUTH_DMASK && reg <= AARCH64_DWARF_PAUTH_CMASK)
+ return tdep->pauth_reg_base + reg - AARCH64_DWARF_PAUTH_DMASK;
+
+ if (reg == AARCH64_DWARF_PAUTH_RA_STATE)
+ return tdep->pauth_ra_state_regnum;
+ }
return -1;
}
{
struct gdbarch *gdbarch = regs->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int elements;
+ struct type *fundamental_type;
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
+ &fundamental_type))
{
- bfd_byte buf[V_REGISTER_SIZE];
- int len = TYPE_LENGTH (type);
+ int len = TYPE_LENGTH (fundamental_type);
+
+ for (int i = 0; i < elements; i++)
+ {
+ int regno = AARCH64_V0_REGNUM + i;
+ /* Enough space for a full vector register. */
+ gdb_byte buf[register_size (gdbarch, regno)];
+ gdb_assert (len <= sizeof (buf));
+
+ if (aarch64_debug)
+ {
+ debug_printf ("read HFA or HVA return value element %d from %s\n",
+ i + 1,
+ gdbarch_register_name (gdbarch, regno));
+ }
+ regs->cooked_read (regno, buf);
- regs->cooked_read (AARCH64_V0_REGNUM, buf);
- memcpy (valbuf, buf, len);
+ memcpy (valbuf, buf, len);
+ valbuf += len;
+ }
}
- else if (TYPE_CODE (type) == TYPE_CODE_INT
- || TYPE_CODE (type) == TYPE_CODE_CHAR
- || TYPE_CODE (type) == TYPE_CODE_BOOL
- || TYPE_CODE (type) == TYPE_CODE_PTR
+ else if (type->code () == TYPE_CODE_INT
+ || type->code () == TYPE_CODE_CHAR
+ || type->code () == TYPE_CODE_BOOL
+ || type->code () == TYPE_CODE_PTR
|| TYPE_IS_REFERENCE (type)
- || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ || type->code () == TYPE_CODE_ENUM)
{
- /* If the the type is a plain integer, then the access is
+ /* If the type is a plain integer, then the access is
straight-forward. Otherwise we have to play around a bit
more. */
int len = TYPE_LENGTH (type);
valbuf += X_REGISTER_SIZE;
}
}
- else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX)
- {
- int regno = AARCH64_V0_REGNUM;
- bfd_byte buf[V_REGISTER_SIZE];
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
- int len = TYPE_LENGTH (target_type);
-
- regs->cooked_read (regno, buf);
- memcpy (valbuf, buf, len);
- valbuf += len;
- regs->cooked_read (regno + 1, buf);
- memcpy (valbuf, buf, len);
- valbuf += len;
- }
- else if (is_hfa_or_hva (type))
- {
- int elements = TYPE_NFIELDS (type);
- struct type *member_type = check_typedef (TYPE_FIELD_TYPE (type, 0));
- int len = TYPE_LENGTH (member_type);
- int i;
-
- for (i = 0; i < elements; i++)
- {
- int regno = AARCH64_V0_REGNUM + i;
- bfd_byte buf[V_REGISTER_SIZE];
-
- if (aarch64_debug)
- {
- debug_printf ("read HFA or HVA return value element %d from %s\n",
- i + 1,
- gdbarch_register_name (gdbarch, regno));
- }
- regs->cooked_read (regno, buf);
-
- memcpy (valbuf, buf, len);
- valbuf += len;
- }
- }
- else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
- && (TYPE_LENGTH (type) == 16 || TYPE_LENGTH (type) == 8))
- {
- /* Short vector is returned in V register. */
- gdb_byte buf[V_REGISTER_SIZE];
-
- regs->cooked_read (AARCH64_V0_REGNUM, buf);
- memcpy (valbuf, buf, TYPE_LENGTH (type));
- }
else
{
/* For a structure or union the behaviour is as if the value had
- been stored to word-aligned memory and then loaded into
- registers with 64-bit load instruction(s). */
+ been stored to word-aligned memory and then loaded into
+ registers with 64-bit load instruction(s). */
int len = TYPE_LENGTH (type);
int regno = AARCH64_X0_REGNUM;
bfd_byte buf[X_REGISTER_SIZE];
aarch64_return_in_memory (struct gdbarch *gdbarch, struct type *type)
{
type = check_typedef (type);
+ int elements;
+ struct type *fundamental_type;
- if (is_hfa_or_hva (type))
+ if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
+ &fundamental_type))
{
/* v0-v7 are used to return values and one register is allocated
for one member. However, HFA or HVA has at most four members. */
if (TYPE_LENGTH (type) > 16)
{
/* PCS B.6 Aggregates larger than 16 bytes are passed by
- invisible reference. */
+ invisible reference. */
return 1;
}
{
struct gdbarch *gdbarch = regs->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int elements;
+ struct type *fundamental_type;
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
+ &fundamental_type))
{
- bfd_byte buf[V_REGISTER_SIZE];
- int len = TYPE_LENGTH (type);
+ int len = TYPE_LENGTH (fundamental_type);
+
+ for (int i = 0; i < elements; i++)
+ {
+ int regno = AARCH64_V0_REGNUM + i;
+ /* Enough space for a full vector register. */
+ gdb_byte tmpbuf[register_size (gdbarch, regno)];
+ gdb_assert (len <= sizeof (tmpbuf));
+
+ if (aarch64_debug)
+ {
+ debug_printf ("write HFA or HVA return value element %d to %s\n",
+ i + 1,
+ gdbarch_register_name (gdbarch, regno));
+ }
- memcpy (buf, valbuf, len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
- regs->cooked_write (AARCH64_V0_REGNUM, buf);
+ memcpy (tmpbuf, valbuf,
+ len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
+ regs->cooked_write (regno, tmpbuf);
+ valbuf += len;
+ }
}
- else if (TYPE_CODE (type) == TYPE_CODE_INT
- || TYPE_CODE (type) == TYPE_CODE_CHAR
- || TYPE_CODE (type) == TYPE_CODE_BOOL
- || TYPE_CODE (type) == TYPE_CODE_PTR
+ else if (type->code () == TYPE_CODE_INT
+ || type->code () == TYPE_CODE_CHAR
+ || type->code () == TYPE_CODE_BOOL
+ || type->code () == TYPE_CODE_PTR
|| TYPE_IS_REFERENCE (type)
- || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ || type->code () == TYPE_CODE_ENUM)
{
if (TYPE_LENGTH (type) <= X_REGISTER_SIZE)
{
}
}
}
- else if (is_hfa_or_hva (type))
- {
- int elements = TYPE_NFIELDS (type);
- struct type *member_type = check_typedef (TYPE_FIELD_TYPE (type, 0));
- int len = TYPE_LENGTH (member_type);
- int i;
-
- for (i = 0; i < elements; i++)
- {
- int regno = AARCH64_V0_REGNUM + i;
- bfd_byte tmpbuf[V_REGISTER_SIZE];
-
- if (aarch64_debug)
- {
- debug_printf ("write HFA or HVA return value element %d to %s\n",
- i + 1,
- gdbarch_register_name (gdbarch, regno));
- }
-
- memcpy (tmpbuf, valbuf, len);
- regs->cooked_write (regno, tmpbuf);
- valbuf += len;
- }
- }
- else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
- && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16))
- {
- /* Short vector. */
- gdb_byte buf[V_REGISTER_SIZE];
-
- memcpy (buf, valbuf, TYPE_LENGTH (type));
- regs->cooked_write (AARCH64_V0_REGNUM, buf);
- }
else
{
/* For a structure or union the behaviour is as if the value had
gdb_byte *readbuf, const gdb_byte *writebuf)
{
- if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
- || TYPE_CODE (valtype) == TYPE_CODE_UNION
- || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+ if (valtype->code () == TYPE_CODE_STRUCT
+ || valtype->code () == TYPE_CODE_UNION
+ || valtype->code () == TYPE_CODE_ARRAY)
{
if (aarch64_return_in_memory (gdbarch, valtype))
{
"b28", "b29", "b30", "b31",
};
- regnum -= gdbarch_num_regs (gdbarch);
+ int p_regnum = regnum - gdbarch_num_regs (gdbarch);
- if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
- return q_name[regnum - AARCH64_Q0_REGNUM];
+ if (p_regnum >= AARCH64_Q0_REGNUM && p_regnum < AARCH64_Q0_REGNUM + 32)
+ return q_name[p_regnum - AARCH64_Q0_REGNUM];
- if (regnum >= AARCH64_D0_REGNUM && regnum < AARCH64_D0_REGNUM + 32)
- return d_name[regnum - AARCH64_D0_REGNUM];
+ if (p_regnum >= AARCH64_D0_REGNUM && p_regnum < AARCH64_D0_REGNUM + 32)
+ return d_name[p_regnum - AARCH64_D0_REGNUM];
- if (regnum >= AARCH64_S0_REGNUM && regnum < AARCH64_S0_REGNUM + 32)
- return s_name[regnum - AARCH64_S0_REGNUM];
+ if (p_regnum >= AARCH64_S0_REGNUM && p_regnum < AARCH64_S0_REGNUM + 32)
+ return s_name[p_regnum - AARCH64_S0_REGNUM];
- if (regnum >= AARCH64_H0_REGNUM && regnum < AARCH64_H0_REGNUM + 32)
- return h_name[regnum - AARCH64_H0_REGNUM];
+ if (p_regnum >= AARCH64_H0_REGNUM && p_regnum < AARCH64_H0_REGNUM + 32)
+ return h_name[p_regnum - AARCH64_H0_REGNUM];
- if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
- return b_name[regnum - AARCH64_B0_REGNUM];
+ if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
+ return b_name[p_regnum - AARCH64_B0_REGNUM];
if (tdep->has_sve ())
{
"v28", "v29", "v30", "v31",
};
- if (regnum >= AARCH64_SVE_V0_REGNUM
- && regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
- return sve_v_name[regnum - AARCH64_SVE_V0_REGNUM];
+ if (p_regnum >= AARCH64_SVE_V0_REGNUM
+ && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
+ return sve_v_name[p_regnum - AARCH64_SVE_V0_REGNUM];
}
+ /* RA_STATE is used for unwinding only. Do not assign it a name - this
+ prevents it from being read by methods such as
+ mi_cmd_trace_frame_collected. */
+ if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
+ return "";
+
internal_error (__FILE__, __LINE__,
_("aarch64_pseudo_register_name: bad register number %d"),
- regnum);
+ p_regnum);
}
/* Implement the "pseudo_register_type" tdesc_arch_data method. */
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- regnum -= gdbarch_num_regs (gdbarch);
+ int p_regnum = regnum - gdbarch_num_regs (gdbarch);
- if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
+ if (p_regnum >= AARCH64_Q0_REGNUM && p_regnum < AARCH64_Q0_REGNUM + 32)
return aarch64_vnq_type (gdbarch);
- if (regnum >= AARCH64_D0_REGNUM && regnum < AARCH64_D0_REGNUM + 32)
+ if (p_regnum >= AARCH64_D0_REGNUM && p_regnum < AARCH64_D0_REGNUM + 32)
return aarch64_vnd_type (gdbarch);
- if (regnum >= AARCH64_S0_REGNUM && regnum < AARCH64_S0_REGNUM + 32)
+ if (p_regnum >= AARCH64_S0_REGNUM && p_regnum < AARCH64_S0_REGNUM + 32)
return aarch64_vns_type (gdbarch);
- if (regnum >= AARCH64_H0_REGNUM && regnum < AARCH64_H0_REGNUM + 32)
+ if (p_regnum >= AARCH64_H0_REGNUM && p_regnum < AARCH64_H0_REGNUM + 32)
return aarch64_vnh_type (gdbarch);
- if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
+ if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
return aarch64_vnb_type (gdbarch);
- if (tdep->has_sve () && regnum >= AARCH64_SVE_V0_REGNUM
- && regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
+ if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM
+ && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
return aarch64_vnv_type (gdbarch);
+ if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
+ return builtin_type (gdbarch)->builtin_uint64;
+
internal_error (__FILE__, __LINE__,
_("aarch64_pseudo_register_type: bad register number %d"),
- regnum);
+ p_regnum);
}
/* Implement the "pseudo_register_reggroup_p" tdesc_arch_data method. */
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- regnum -= gdbarch_num_regs (gdbarch);
+ int p_regnum = regnum - gdbarch_num_regs (gdbarch);
- if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
+ if (p_regnum >= AARCH64_Q0_REGNUM && p_regnum < AARCH64_Q0_REGNUM + 32)
return group == all_reggroup || group == vector_reggroup;
- else if (regnum >= AARCH64_D0_REGNUM && regnum < AARCH64_D0_REGNUM + 32)
+ else if (p_regnum >= AARCH64_D0_REGNUM && p_regnum < AARCH64_D0_REGNUM + 32)
return (group == all_reggroup || group == vector_reggroup
|| group == float_reggroup);
- else if (regnum >= AARCH64_S0_REGNUM && regnum < AARCH64_S0_REGNUM + 32)
+ else if (p_regnum >= AARCH64_S0_REGNUM && p_regnum < AARCH64_S0_REGNUM + 32)
return (group == all_reggroup || group == vector_reggroup
|| group == float_reggroup);
- else if (regnum >= AARCH64_H0_REGNUM && regnum < AARCH64_H0_REGNUM + 32)
+ else if (p_regnum >= AARCH64_H0_REGNUM && p_regnum < AARCH64_H0_REGNUM + 32)
return group == all_reggroup || group == vector_reggroup;
- else if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
+ else if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
return group == all_reggroup || group == vector_reggroup;
- else if (tdep->has_sve () && regnum >= AARCH64_SVE_V0_REGNUM
- && regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
+ else if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM
+ && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
return group == all_reggroup || group == vector_reggroup;
+ /* RA_STATE is used for unwinding only. Do not assign it to any groups. */
+ if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
+ return 0;
return group == all_reggroup;
}
{
/* 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;
};
/* The address where the instruction will be executed at. */
CORE_ADDR new_addr;
/* Buffer of instructions to be copied to NEW_ADDR to execute. */
- uint32_t insn_buf[DISPLACED_MODIFIED_INSNS];
+ uint32_t insn_buf[AARCH64_DISPLACED_MODIFIED_INSNS];
/* Number of instructions in INSN_BUF. */
unsigned insn_count;
/* Registers when doing displaced stepping. */
*/
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)
dsd.insn_count = 0;
aarch64_relocate_instruction (insn, &visitor,
(struct aarch64_insn_data *) &dsd);
- gdb_assert (dsd.insn_count <= DISPLACED_MODIFIED_INSNS);
+ gdb_assert (dsd.insn_count <= AARCH64_DISPLACED_MODIFIED_INSNS);
if (dsd.insn_count != 0)
{
relocated instruction(s) there. */
for (i = 0; i < dsd.insn_count; i++)
{
- if (debug_displaced)
- {
- debug_printf ("displaced: writing insn ");
- debug_printf ("%.8x", dsd.insn_buf[i]);
- debug_printf (" at %s\n", paddress (gdbarch, to + i * 4));
- }
+ displaced_debug_printf ("writing insn %.8x at %s",
+ dsd.insn_buf[i],
+ paddress (gdbarch, to + i * 4));
+
write_memory_unsigned_integer (to + i * 4, 4, byte_order_for_code,
(ULONGEST) dsd.insn_buf[i]);
}
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);
+
+ displaced_debug_printf ("PC after stepping: %s (was %s).",
+ paddress (gdbarch, pc), paddress (gdbarch, to));
+
if (dsc->cond)
{
- ULONGEST pc;
+ displaced_debug_printf ("[Conditional] pc_adjust before: %d",
+ 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");
+
+ displaced_debug_printf ("[Conditional] pc_adjust after: %d",
+ dsc->pc_adjust);
}
+ displaced_debug_printf ("%s PC by %d",
+ dsc->pc_adjust ? "adjusting" : "not adjusting",
+ dsc->pc_adjust);
+
if (dsc->pc_adjust != 0)
{
- if (debug_displaced)
+ /* 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)
{
- debug_printf ("displaced: fixup: set PC to %s:%d\n",
- paddress (gdbarch, from), dsc->pc_adjust);
+ displaced_debug_printf ("PC did not move. Discarding PC adjustment.");
+ dsc->pc_adjust = 0;
}
+
+ displaced_debug_printf ("fixup: set PC to %s:%d",
+ paddress (gdbarch, from), dsc->pc_adjust);
+
regcache_cooked_write_unsigned (regs, AARCH64_PC_REGNUM,
from + dsc->pc_adjust);
}
/* Implement the "displaced_step_hw_singlestep" gdbarch method. */
-int
-aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch,
- struct displaced_step_closure *closure)
+bool
+aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch)
{
- return 1;
+ return true;
}
/* Get the correct target description for the given VQ value.
(It is not possible to set VQ to zero on an SVE system). */
const target_desc *
-aarch64_read_description (uint64_t vq)
+aarch64_read_description (uint64_t vq, bool pauth_p)
{
if (vq > AARCH64_MAX_SVE_VQ)
error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq,
AARCH64_MAX_SVE_VQ);
- struct target_desc *tdesc = tdesc_aarch64_list[vq];
+ struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p];
if (tdesc == NULL)
{
- tdesc = aarch64_create_target_description (vq);
- tdesc_aarch64_list[vq] = tdesc;
+ tdesc = aarch64_create_target_description (vq, pauth_p);
+ tdesc_aarch64_list[vq][pauth_p] = tdesc;
}
return tdesc;
return sve_vq_from_vl (vl);
}
+/* Add all the expected register sets into GDBARCH. */
+
+static void
+aarch64_add_reggroups (struct gdbarch *gdbarch)
+{
+ reggroup_add (gdbarch, general_reggroup);
+ reggroup_add (gdbarch, float_reggroup);
+ reggroup_add (gdbarch, system_reggroup);
+ reggroup_add (gdbarch, vector_reggroup);
+ reggroup_add (gdbarch, all_reggroup);
+ reggroup_add (gdbarch, save_reggroup);
+ reggroup_add (gdbarch, restore_reggroup);
+}
+
+/* Implement the "cannot_store_register" gdbarch method. */
+
+static int
+aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->has_pauth ())
+ return 0;
+
+ /* Pointer authentication registers are read-only. */
+ return (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
+ || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
+}
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
static struct gdbarch *
aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
- struct gdbarch_tdep *tdep;
- struct gdbarch *gdbarch;
- struct gdbarch_list *best_arch;
- struct tdesc_arch_data *tdesc_data = NULL;
- const struct target_desc *tdesc = info.target_desc;
- int i;
- int valid_p = 1;
- const struct tdesc_feature *feature_core;
- const struct tdesc_feature *feature_fpu;
- const struct tdesc_feature *feature_sve;
- int num_regs = 0;
- int num_pseudo_regs = 0;
+ const struct tdesc_feature *feature_core, *feature_fpu, *feature_sve;
+ const struct tdesc_feature *feature_pauth;
+ bool valid_p = true;
+ int i, num_regs = 0, num_pseudo_regs = 0;
+ int first_pauth_regnum = -1, pauth_ra_state_offset = -1;
+
+ /* Use the vector length passed via the target info. Here -1 is used for no
+ SVE, and 0 is unset. If unset then use the vector length from the existing
+ tdesc. */
+ uint64_t vq = 0;
+ if (info.id == (int *) -1)
+ vq = 0;
+ else if (info.id != 0)
+ vq = (uint64_t) info.id;
+ else
+ vq = aarch64_get_tdesc_vq (info.target_desc);
- /* Ensure we always have a target description. */
- if (!tdesc_has_registers (tdesc))
- tdesc = aarch64_read_description (0);
+ if (vq > AARCH64_MAX_SVE_VQ)
+ internal_error (__FILE__, __LINE__, _("VQ out of bounds: %s (max %d)"),
+ pulongest (vq), AARCH64_MAX_SVE_VQ);
+
+ /* If there is already a candidate, use it. */
+ for (gdbarch_list *best_arch = gdbarch_list_lookup_by_info (arches, &info);
+ best_arch != nullptr;
+ best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (best_arch->gdbarch);
+ if (tdep && tdep->vq == vq)
+ return best_arch->gdbarch;
+ }
+
+ /* Ensure we always have a target descriptor, and that it is for the given VQ
+ value. */
+ const struct target_desc *tdesc = info.target_desc;
+ if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc))
+ tdesc = aarch64_read_description (vq, false);
gdb_assert (tdesc);
- feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core");
+ feature_core = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.core");
feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
+ feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth");
- if (feature_core == NULL)
- return NULL;
+ if (feature_core == nullptr)
+ return nullptr;
- tdesc_data = tdesc_data_alloc ();
+ tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
/* Validate the description provides the mandatory core R registers
and allocate their numbers. */
for (i = 0; i < ARRAY_SIZE (aarch64_r_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_core, tdesc_data,
+ valid_p &= tdesc_numbered_register (feature_core, tdesc_data.get (),
AARCH64_X0_REGNUM + i,
aarch64_r_register_names[i]);
num_regs = AARCH64_X0_REGNUM + i;
/* Add the V registers. */
- if (feature_fpu != NULL)
+ if (feature_fpu != nullptr)
{
- if (feature_sve != NULL)
+ if (feature_sve != nullptr)
error (_("Program contains both fpu and SVE features."));
/* Validate the description provides the mandatory V registers
and allocate their numbers. */
for (i = 0; i < ARRAY_SIZE (aarch64_v_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data,
+ valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (),
AARCH64_V0_REGNUM + i,
aarch64_v_register_names[i]);
}
/* Add the SVE registers. */
- if (feature_sve != NULL)
+ if (feature_sve != nullptr)
{
/* Validate the description provides the mandatory SVE registers
and allocate their numbers. */
for (i = 0; i < ARRAY_SIZE (aarch64_sve_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_sve, tdesc_data,
+ valid_p &= tdesc_numbered_register (feature_sve, tdesc_data.get (),
AARCH64_SVE_Z0_REGNUM + i,
aarch64_sve_register_names[i]);
num_pseudo_regs += 32; /* add the Vn register pseudos. */
}
- if (feature_fpu != NULL || feature_sve != NULL)
+ if (feature_fpu != nullptr || feature_sve != nullptr)
{
num_pseudo_regs += 32; /* add the Qn scalar register pseudos */
num_pseudo_regs += 32; /* add the Dn scalar register pseudos */
num_pseudo_regs += 32; /* add the Bn scalar register pseudos */
}
- if (!valid_p)
+ /* Add the pauth registers. */
+ if (feature_pauth != NULL)
{
- tdesc_data_cleanup (tdesc_data);
- return NULL;
+ first_pauth_regnum = num_regs;
+ pauth_ra_state_offset = num_pseudo_regs;
+ /* Validate the descriptor provides the mandatory PAUTH registers and
+ allocate their numbers. */
+ for (i = 0; i < ARRAY_SIZE (aarch64_pauth_register_names); i++)
+ valid_p &= tdesc_numbered_register (feature_pauth, tdesc_data.get (),
+ first_pauth_regnum + i,
+ aarch64_pauth_register_names[i]);
+
+ num_regs += i;
+ num_pseudo_regs += 1; /* Count RA_STATE pseudo register. */
}
+ if (!valid_p)
+ return nullptr;
+
/* AArch64 code is always little-endian. */
info.byte_order_for_code = BFD_ENDIAN_LITTLE;
- /* If there is already a candidate, use it. */
- for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
- best_arch != NULL;
- best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
- {
- /* Found a match. */
- break;
- }
-
- if (best_arch != NULL)
- {
- if (tdesc_data != NULL)
- tdesc_data_cleanup (tdesc_data);
- return best_arch->gdbarch;
- }
-
- tdep = XCNEW (struct gdbarch_tdep);
- gdbarch = gdbarch_alloc (&info, tdep);
+ struct gdbarch_tdep *tdep = XCNEW (struct gdbarch_tdep);
+ struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
/* This should be low enough for everything. */
tdep->lowest_pc = 0x20;
tdep->jb_pc = -1; /* Longjump support not enabled by default. */
tdep->jb_elt_size = 8;
- tdep->vq = aarch64_get_tdesc_vq (tdesc);
+ tdep->vq = vq;
+ tdep->pauth_reg_base = first_pauth_regnum;
+ tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1
+ : pauth_ra_state_offset + num_regs;
set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
- /* Frame handling. */
- set_gdbarch_dummy_id (gdbarch, aarch64_dummy_id);
- set_gdbarch_unwind_pc (gdbarch, aarch64_unwind_pc);
- set_gdbarch_unwind_sp (gdbarch, aarch64_unwind_sp);
-
/* Advance PC across function entry code. */
set_gdbarch_skip_prologue (gdbarch, aarch64_skip_prologue);
set_tdesc_pseudo_register_type (gdbarch, aarch64_pseudo_register_type);
set_tdesc_pseudo_register_reggroup_p (gdbarch,
aarch64_pseudo_register_reggroup_p);
+ set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
/* ABI */
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+ set_gdbarch_type_align (gdbarch, aarch64_type_align);
/* Internal <-> external register number maps. */
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, aarch64_dwarf_reg_to_regnum);
/* Virtual tables. */
set_gdbarch_vbit_in_delta (gdbarch, 1);
+ /* Register architecture. */
+ aarch64_add_reggroups (gdbarch);
+
/* Hook in the ABI-specific overrides, if they have been registered. */
info.target_desc = tdesc;
- info.tdesc_data = tdesc_data;
+ info.tdesc_data = tdesc_data.get ();
gdbarch_init_osabi (info, gdbarch);
dwarf2_frame_set_init_reg (gdbarch, aarch64_dwarf2_frame_init_reg);
+ /* Register DWARF CFA vendor handler. */
+ 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);
set_gdbarch_gen_return_address (gdbarch, aarch64_gen_return_address);
- tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+ set_gdbarch_get_pc_address_flags (gdbarch, aarch64_get_pc_address_flags);
+
+ tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
/* Add standard register aliases. */
for (i = 0; i < ARRAY_SIZE (aarch64_register_aliases); i++)
value_of_aarch64_user_reg,
&aarch64_register_aliases[i].regnum);
+ register_aarch64_ravenscar_ops (gdbarch);
+
return 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);
selftests::aarch64_analyze_prologue_test);
selftests::register_test ("aarch64-process-record",
selftests::aarch64_process_record_test);
- selftests::record_xml_tdesc ("aarch64.xml",
- aarch64_create_target_description (0));
#endif
}
/* AArch64 process record-replay related structures, defines etc. */
#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \
- do \
- { \
- unsigned int reg_len = LENGTH; \
- if (reg_len) \
- { \
- REGS = XNEWVEC (uint32_t, reg_len); \
- memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \
- } \
- } \
- while (0)
+ do \
+ { \
+ unsigned int reg_len = LENGTH; \
+ if (reg_len) \
+ { \
+ REGS = XNEWVEC (uint32_t, reg_len); \
+ memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \
+ } \
+ } \
+ while (0)
#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \
- do \
- { \
- unsigned int mem_len = LENGTH; \
- if (mem_len) \
- { \
- MEMS = XNEWVEC (struct aarch64_mem_r, mem_len); \
- memcpy(&MEMS->len, &RECORD_BUF[0], \
- sizeof(struct aarch64_mem_r) * LENGTH); \
- } \
- } \
- while (0)
+ do \
+ { \
+ unsigned int mem_len = LENGTH; \
+ if (mem_len) \
+ { \
+ MEMS = XNEWVEC (struct aarch64_mem_r, mem_len); \
+ memcpy(&MEMS->len, &RECORD_BUF[0], \
+ sizeof(struct aarch64_mem_r) * LENGTH); \
+ } \
+ } \
+ while (0)
/* AArch64 record/replay structures and enumerations. */
}
else if (insn_bits21_23 == 0x04 || insn_bits21_23 == 0x06)
{
- /* CConditional select. */
+ /* Conditional select. */
/* Data-processing (2 source). */
/* Data-processing (1 source). */
record_buf[0] = reg_rd;
uint8_t sindex, scale, selem, esize, replicate = 0;
scale = opcode_bits >> 2;
selem = ((opcode_bits & 0x02) |
- bit (aarch64_insn_r->aarch64_insn, 21)) + 1;
+ bit (aarch64_insn_r->aarch64_insn, 21)) + 1;
switch (scale)
- {
- case 1:
- if (size_bits & 0x01)
- return AARCH64_RECORD_UNKNOWN;
- break;
- case 2:
- if ((size_bits >> 1) & 0x01)
- return AARCH64_RECORD_UNKNOWN;
- if (size_bits & 0x01)
- {
- if (!((opcode_bits >> 1) & 0x01))
- scale = 3;
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- break;
- case 3:
- if (bit (aarch64_insn_r->aarch64_insn, 22) && !(opcode_bits & 0x01))
- {
- scale = size_bits;
- replicate = 1;
- break;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- default:
- break;
- }
+ {
+ case 1:
+ if (size_bits & 0x01)
+ return AARCH64_RECORD_UNKNOWN;
+ break;
+ case 2:
+ if ((size_bits >> 1) & 0x01)
+ return AARCH64_RECORD_UNKNOWN;
+ if (size_bits & 0x01)
+ {
+ if (!((opcode_bits >> 1) & 0x01))
+ scale = 3;
+ else
+ return AARCH64_RECORD_UNKNOWN;
+ }
+ break;
+ case 3:
+ if (bit (aarch64_insn_r->aarch64_insn, 22) && !(opcode_bits & 0x01))
+ {
+ scale = size_bits;
+ replicate = 1;
+ break;
+ }
+ else
+ return AARCH64_RECORD_UNKNOWN;
+ default:
+ break;
+ }
esize = 8 << scale;
if (replicate)
- for (sindex = 0; sindex < selem; sindex++)
- {
- record_buf[reg_index++] = reg_rt + AARCH64_V0_REGNUM;
- reg_rt = (reg_rt + 1) % 32;
- }
+ for (sindex = 0; sindex < selem; sindex++)
+ {
+ record_buf[reg_index++] = reg_rt + AARCH64_V0_REGNUM;
+ reg_rt = (reg_rt + 1) % 32;
+ }
else
- {
- for (sindex = 0; sindex < selem; sindex++)
+ {
+ for (sindex = 0; sindex < selem; sindex++)
{
if (bit (aarch64_insn_r->aarch64_insn, 22))
record_buf[reg_index++] = reg_rt + AARCH64_V0_REGNUM;
addr_offset = addr_offset + (esize / 8);
reg_rt = (reg_rt + 1) % 32;
}
- }
+ }
}
/* Load/store multiple structure. */
else
esize = 8 << size_bits;
if (bit (aarch64_insn_r->aarch64_insn, 30))
- elements = 128 / esize;
+ elements = 128 / esize;
else
- elements = 64 / esize;
+ elements = 64 / esize;
switch (opcode_bits)
- {
- /*LD/ST4 (4 Registers). */
- case 0:
- rpt = 1;
- selem = 4;
- break;
- /*LD/ST1 (4 Registers). */
- case 2:
- rpt = 4;
- selem = 1;
- break;
- /*LD/ST3 (3 Registers). */
- case 4:
- rpt = 1;
- selem = 3;
- break;
- /*LD/ST1 (3 Registers). */
- case 6:
- rpt = 3;
- selem = 1;
- break;
- /*LD/ST1 (1 Register). */
- case 7:
- rpt = 1;
- selem = 1;
- break;
- /*LD/ST2 (2 Registers). */
- case 8:
- rpt = 1;
- selem = 2;
- break;
- /*LD/ST1 (2 Registers). */
- case 10:
- rpt = 2;
- selem = 1;
- break;
- default:
- return AARCH64_RECORD_UNSUPPORTED;
- break;
- }
+ {
+ /*LD/ST4 (4 Registers). */
+ case 0:
+ rpt = 1;
+ selem = 4;
+ break;
+ /*LD/ST1 (4 Registers). */
+ case 2:
+ rpt = 4;
+ selem = 1;
+ break;
+ /*LD/ST3 (3 Registers). */
+ case 4:
+ rpt = 1;
+ selem = 3;
+ break;
+ /*LD/ST1 (3 Registers). */
+ case 6:
+ rpt = 3;
+ selem = 1;
+ break;
+ /*LD/ST1 (1 Register). */
+ case 7:
+ rpt = 1;
+ selem = 1;
+ break;
+ /*LD/ST2 (2 Registers). */
+ case 8:
+ rpt = 1;
+ selem = 2;
+ break;
+ /*LD/ST1 (2 Registers). */
+ case 10:
+ rpt = 2;
+ selem = 1;
+ break;
+ default:
+ return AARCH64_RECORD_UNSUPPORTED;
+ break;
+ }
for (rindex = 0; rindex < rpt; rindex++)
- for (eindex = 0; eindex < elements; eindex++)
- {
- uint8_t reg_tt, sindex;
- reg_tt = (reg_rt + rindex) % 32;
- for (sindex = 0; sindex < selem; sindex++)
- {
- if (bit (aarch64_insn_r->aarch64_insn, 22))
- record_buf[reg_index++] = reg_tt + AARCH64_V0_REGNUM;
- else
- {
- record_buf_mem[mem_index++] = esize / 8;
- record_buf_mem[mem_index++] = address + addr_offset;
- }
- addr_offset = addr_offset + (esize / 8);
- reg_tt = (reg_tt + 1) % 32;
- }
- }
+ for (eindex = 0; eindex < elements; eindex++)
+ {
+ uint8_t reg_tt, sindex;
+ reg_tt = (reg_rt + rindex) % 32;
+ for (sindex = 0; sindex < selem; sindex++)
+ {
+ if (bit (aarch64_insn_r->aarch64_insn, 22))
+ record_buf[reg_index++] = reg_tt + AARCH64_V0_REGNUM;
+ else
+ {
+ record_buf_mem[mem_index++] = esize / 8;
+ record_buf_mem[mem_index++] = address + addr_offset;
+ }
+ addr_offset = addr_offset + (esize / 8);
+ reg_tt = (reg_tt + 1) % 32;
+ }
+ }
}
if (bit (aarch64_insn_r->aarch64_insn, 23))
aarch64_insn_r->reg_rec_count = reg_index;
aarch64_insn_r->mem_rec_count = mem_index / 2;
MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count,
- record_buf_mem);
+ record_buf_mem);
REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
+ record_buf);
return AARCH64_RECORD_SUCCESS;
}
if (record_debug)
debug_printf ("Process record: load register (literal)\n");
if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
+ record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
else
- record_buf[0] = reg_rt;
+ record_buf[0] = reg_rt;
aarch64_insn_r->reg_rec_count = 1;
}
/* All types of load/store pair instructions decoding. */
debug_printf ("Process record: load/store pair\n");
if (ld_flag)
- {
- if (vector_flag)
- {
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM;
- }
- else
- {
- record_buf[0] = reg_rt;
- record_buf[1] = reg_rt2;
- }
- aarch64_insn_r->reg_rec_count = 2;
- }
+ {
+ if (vector_flag)
+ {
+ record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
+ record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM;
+ }
+ else
+ {
+ record_buf[0] = reg_rt;
+ record_buf[1] = reg_rt2;
+ }
+ aarch64_insn_r->reg_rec_count = 2;
+ }
else
- {
- uint16_t imm7_off;
- imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21);
- if (!vector_flag)
- size_bits = size_bits >> 1;
- datasize = 8 << (2 + size_bits);
- offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off;
- offset = offset << (2 + size_bits);
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23))
- {
- if (imm7_off & 0x40)
- address = address - offset;
- else
- address = address + offset;
- }
-
- record_buf_mem[0] = datasize / 8;
- record_buf_mem[1] = address;
- record_buf_mem[2] = datasize / 8;
- record_buf_mem[3] = address + (datasize / 8);
- aarch64_insn_r->mem_rec_count = 2;
- }
+ {
+ uint16_t imm7_off;
+ imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21);
+ if (!vector_flag)
+ size_bits = size_bits >> 1;
+ datasize = 8 << (2 + size_bits);
+ offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off;
+ offset = offset << (2 + size_bits);
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
+ &address);
+ if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23))
+ {
+ if (imm7_off & 0x40)
+ address = address - offset;
+ else
+ address = address + offset;
+ }
+
+ record_buf_mem[0] = datasize / 8;
+ record_buf_mem[1] = address;
+ record_buf_mem[2] = datasize / 8;
+ record_buf_mem[3] = address + (datasize / 8);
+ aarch64_insn_r->mem_rec_count = 2;
+ }
if (bit (aarch64_insn_r->aarch64_insn, 23))
- record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
+ record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
}
/* Load/store register (unsigned immediate) instructions. */
else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x03)
}
if (!ld_flag)
- {
- offset = bits (aarch64_insn_r->aarch64_insn, 10, 21);
- datasize = 8 << size_bits;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- offset = offset << size_bits;
- address = address + offset;
-
- record_buf_mem[0] = datasize >> 3;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- }
+ {
+ offset = bits (aarch64_insn_r->aarch64_insn, 10, 21);
+ datasize = 8 << size_bits;
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
+ &address);
+ offset = offset << size_bits;
+ address = address + offset;
+
+ record_buf_mem[0] = datasize >> 3;
+ record_buf_mem[1] = address;
+ aarch64_insn_r->mem_rec_count = 1;
+ }
else
- {
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
+ {
+ if (vector_flag)
+ record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
+ else
+ record_buf[0] = reg_rt;
+ aarch64_insn_r->reg_rec_count = 1;
+ }
}
/* Load/store register (register offset) instructions. */
else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03
debug_printf ("Process record: load/store (register offset)\n");
opc = bits (aarch64_insn_r->aarch64_insn, 22, 23);
if (!(opc >> 1))
- if (opc & 0x01)
- ld_flag = 0x01;
- else
- ld_flag = 0x0;
+ if (opc & 0x01)
+ ld_flag = 0x01;
+ else
+ ld_flag = 0x0;
else
- if (size_bits != 0x03)
- ld_flag = 0x01;
- else
- return AARCH64_RECORD_UNKNOWN;
+ if (size_bits != 0x03)
+ ld_flag = 0x01;
+ else
+ return AARCH64_RECORD_UNKNOWN;
if (!ld_flag)
- {
- ULONGEST reg_rm_val;
-
- regcache_raw_read_unsigned (aarch64_insn_r->regcache,
- bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val);
- if (bit (aarch64_insn_r->aarch64_insn, 12))
- offset = reg_rm_val << size_bits;
- else
- offset = reg_rm_val;
- datasize = 8 << size_bits;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- address = address + offset;
- record_buf_mem[0] = datasize >> 3;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- }
+ {
+ ULONGEST reg_rm_val;
+
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache,
+ bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val);
+ if (bit (aarch64_insn_r->aarch64_insn, 12))
+ offset = reg_rm_val << size_bits;
+ else
+ offset = reg_rm_val;
+ datasize = 8 << size_bits;
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
+ &address);
+ address = address + offset;
+ record_buf_mem[0] = datasize >> 3;
+ record_buf_mem[1] = address;
+ aarch64_insn_r->mem_rec_count = 1;
+ }
else
- {
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
+ {
+ if (vector_flag)
+ record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
+ else
+ record_buf[0] = reg_rt;
+ aarch64_insn_r->reg_rec_count = 1;
+ }
}
/* Load/store register (immediate and unprivileged) instructions. */
else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03
}
opc = bits (aarch64_insn_r->aarch64_insn, 22, 23);
if (!(opc >> 1))
- if (opc & 0x01)
- ld_flag = 0x01;
- else
- ld_flag = 0x0;
+ if (opc & 0x01)
+ ld_flag = 0x01;
+ else
+ ld_flag = 0x0;
else
- if (size_bits != 0x03)
- ld_flag = 0x01;
- else
- return AARCH64_RECORD_UNKNOWN;
+ if (size_bits != 0x03)
+ ld_flag = 0x01;
+ else
+ return AARCH64_RECORD_UNKNOWN;
if (!ld_flag)
- {
- uint16_t imm9_off;
- imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20);
- offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off;
- datasize = 8 << size_bits;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- if (insn_bits10_11 != 0x01)
- {
- if (imm9_off & 0x0100)
- address = address - offset;
- else
- address = address + offset;
- }
- record_buf_mem[0] = datasize >> 3;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- }
+ {
+ uint16_t imm9_off;
+ imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20);
+ offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off;
+ datasize = 8 << size_bits;
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
+ &address);
+ if (insn_bits10_11 != 0x01)
+ {
+ if (imm9_off & 0x0100)
+ address = address - offset;
+ else
+ address = address + offset;
+ }
+ record_buf_mem[0] = datasize >> 3;
+ record_buf_mem[1] = address;
+ aarch64_insn_r->mem_rec_count = 1;
+ }
else
- {
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
+ {
+ if (vector_flag)
+ record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
+ else
+ record_buf[0] = reg_rt;
+ aarch64_insn_r->reg_rec_count = 1;
+ }
if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03)
- record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
+ record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
}
/* Advanced SIMD load/store instructions. */
else
return aarch64_record_asimd_load_store (aarch64_insn_r);
MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count,
- record_buf_mem);
+ record_buf_mem);
REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
+ record_buf);
return AARCH64_RECORD_SUCCESS;
}
record_buf[0] = AARCH64_CPSR_REGNUM;
}
/* Floating point - data processing (2-source) and
- conditional select instructions. */
+ conditional select instructions. */
else if (insn_bits10_11 == 0x02 || insn_bits10_11 == 0x03)
{
if (record_debug)
}
else
return AARCH64_RECORD_UNKNOWN;
- }
+ }
else
return AARCH64_RECORD_UNKNOWN;
- }
+ }
else
return AARCH64_RECORD_UNKNOWN;
}