#include "vec.h"
#include "features/arm-with-m.c"
+#include "features/arm-with-iwmmxt.c"
+#include "features/arm-with-vfpv2.c"
+#include "features/arm-with-vfpv3.c"
+#include "features/arm-with-neon.c"
static int arm_debug;
static const char *arm_fallback_mode_string = "auto";
static const char *arm_force_mode_string = "auto";
+/* Internal override of the execution mode. -1 means no override,
+ 0 means override to ARM mode, 1 means override to Thumb mode.
+ The effect is the same as if arm_force_mode has been set by the
+ user (except the internal override has precedence over a user's
+ arm_force_mode override). */
+static int arm_override_mode = -1;
+
/* Number of different reg name sets (options). */
static int num_disassembly_options;
static void convert_to_extended (const struct floatformat *, void *,
const void *, int);
-static void arm_neon_quad_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int regnum, gdb_byte *buf);
+static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, gdb_byte *buf);
static void arm_neon_quad_write (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum, const gdb_byte *buf);
/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */
-static int
+int
arm_psr_thumb_bit (struct gdbarch *gdbarch)
{
if (gdbarch_tdep (gdbarch)->is_m)
return 0;
}
-static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame,
- CORE_ADDR pc, int insert_bkpt);
-
/* Determine if the program counter specified in MEMADDR is in a Thumb
function. This function should be called for addresses unrelated to
any executing frame; otherwise, prefer arm_frame_is_thumb. */
-static int
+int
arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
{
struct obj_section *sec;
struct minimal_symbol *sym;
char type;
+ struct displaced_step_closure* dsc
+ = get_displaced_step_closure_by_addr(memaddr);
+
+ /* If checking the mode of displaced instruction in copy area, the mode
+ should be determined by instruction on the original address. */
+ if (dsc)
+ {
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: check mode of %.8lx instead of %.8lx\n",
+ (unsigned long) dsc->insn_addr,
+ (unsigned long) memaddr);
+ memaddr = dsc->insn_addr;
+ }
/* If bit 0 of the address is set, assume this is a Thumb address. */
if (IS_THUMB_ADDR (memaddr))
return 1;
+ /* Respect internal mode override if active. */
+ if (arm_override_mode != -1)
+ return arm_override_mode;
+
/* If the user wants to override the symbol table, let him. */
if (strcmp (arm_force_mode_string, "arm") == 0)
return 0;
target, then trust the current value of $cpsr. This lets
"display/i $pc" always show the correct mode (though if there is
a symbol table we will not reach here, so it still may not be
- displayed in the mode it will be executed).
-
- As a further heuristic if we detect that we are doing a single-step we
- see what state executing the current instruction ends up with us being
- in. */
+ displayed in the mode it will be executed). */
if (target_has_registers)
- {
- struct frame_info *current_frame = get_current_frame ();
- CORE_ADDR current_pc = get_frame_pc (current_frame);
- int is_thumb = arm_frame_is_thumb (current_frame);
- CORE_ADDR next_pc;
- if (memaddr == current_pc)
- return is_thumb;
- else
- {
- struct gdbarch *gdbarch = get_frame_arch (current_frame);
- next_pc = arm_get_next_pc_raw (current_frame, current_pc, FALSE);
- if (memaddr == gdbarch_addr_bits_remove (gdbarch, next_pc))
- return IS_THUMB_ADDR (next_pc);
- else
- return is_thumb;
- }
- }
+ return arm_frame_is_thumb (get_current_frame ());
/* Otherwise we're out of luck; we assume ARM. */
return 0;
}
/* Return 1 if PC is the start of a compiler helper function which
- can be safely ignored during prologue skipping. */
+ can be safely ignored during prologue skipping. IS_THUMB is true
+ if the function is known to be a Thumb function due to the way it
+ is being called. */
static int
-skip_prologue_function (CORE_ADDR pc)
+skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
{
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
struct minimal_symbol *msym;
- const char *name;
msym = lookup_minimal_symbol_by_pc (pc);
- if (msym == NULL || SYMBOL_VALUE_ADDRESS (msym) != pc)
- return 0;
+ if (msym != NULL
+ && SYMBOL_VALUE_ADDRESS (msym) == pc
+ && SYMBOL_LINKAGE_NAME (msym) != NULL)
+ {
+ const char *name = SYMBOL_LINKAGE_NAME (msym);
- name = SYMBOL_LINKAGE_NAME (msym);
- if (name == NULL)
- return 0;
+ /* The GNU linker's Thumb call stub to foo is named
+ __foo_from_thumb. */
+ if (strstr (name, "_from_thumb") != NULL)
+ name += 2;
- /* The GNU linker's Thumb call stub to foo is named
- __foo_from_thumb. */
- if (strstr (name, "_from_thumb") != NULL)
- name += 2;
+ /* On soft-float targets, __truncdfsf2 is called to convert promoted
+ arguments to their argument types in non-prototyped
+ functions. */
+ if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
+ return 1;
+ if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+ return 1;
- /* On soft-float targets, __truncdfsf2 is called to convert promoted
- arguments to their argument types in non-prototyped
- functions. */
- if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
- return 1;
- if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
- return 1;
+ /* Internal functions related to thread-local storage. */
+ if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
+ return 1;
+ if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
+ return 1;
+ }
+ else
+ {
+ /* If we run against a stripped glibc, we may be unable to identify
+ special functions by name. Check for one important case,
+ __aeabi_read_tp, by comparing the *code* against the default
+ implementation (this is hand-written ARM assembler in glibc). */
- /* Internal functions related to thread-local storage. */
- if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
- return 1;
- if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
- return 1;
+ if (!is_thumb
+ && read_memory_unsigned_integer (pc, 4, byte_order_for_code)
+ == 0xe3e00a0f /* mov r0, #0xffff0fff */
+ && read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code)
+ == 0xe240f01f) /* sub pc, r0, #31 */
+ return 1;
+ }
return 0;
}
if (bit (inst2, 12) == 0)
nextpc = nextpc & 0xfffffffc;
- if (!skip_prologue_function (nextpc))
+ if (!skip_prologue_function (gdbarch, nextpc,
+ bit (inst2, 12) != 0))
break;
}
instruction sequence is not for stack protector. If symbol is
removed, we conservatively think this sequence is for stack protector. */
if (stack_chk_guard
- && strcmp (SYMBOL_LINKAGE_NAME(stack_chk_guard), "__stack_chk_guard"))
+ && strncmp (SYMBOL_LINKAGE_NAME (stack_chk_guard), "__stack_chk_guard",
+ strlen ("__stack_chk_guard")) != 0)
return pc;
if (is_thumb)
the stack. */
CORE_ADDR dest = BranchDest (current_pc, insn);
- if (skip_prologue_function (dest))
+ if (skip_prologue_function (gdbarch, dest, 0))
continue;
else
break;
else if (arm_instruction_changes_pc (insn))
/* Don't scan past anything that might change control flow. */
break;
- else if ((insn & 0xfe500000) == 0xe8100000) /* ldm */
- {
- /* Ignore block loads from the stack, potentially copying
- parameters from memory. */
- if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- continue;
- else
- break;
- }
- else if ((insn & 0xfc500000) == 0xe4100000)
- {
- /* Similarly ignore single loads from the stack. */
- if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- continue;
- else
- break;
- }
+ else if ((insn & 0xfe500000) == 0xe8100000 /* ldm */
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ /* Ignore block loads from the stack, potentially copying
+ parameters from memory. */
+ continue;
+ else if ((insn & 0xfc500000) == 0xe4100000
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ /* Similarly ignore single loads from the stack. */
+ continue;
else if ((insn & 0xffff0ff0) == 0xe1a00000)
/* MOV Rd, Rm. Skip register copies, i.e. saves to another
register instead of the stack. */
struct frame_unwind arm_prologue_unwind = {
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
arm_prologue_this_id,
arm_prologue_prev_register,
NULL,
static void
arm_exidx_new_objfile (struct objfile *objfile)
{
- struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ struct cleanup *cleanups;
struct arm_exidx_data *data;
asection *exidx, *extab;
bfd_vma exidx_vma = 0, extab_vma = 0;
/* If we've already touched this file, do nothing. */
if (!objfile || objfile_data (objfile, arm_exidx_data_key) != NULL)
return;
+ cleanups = make_cleanup (null_cleanup, NULL);
/* Read contents of exception table and index. */
exidx = bfd_get_section_by_name (objfile->obfd, ".ARM.exidx");
struct frame_unwind arm_exidx_unwind = {
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
arm_prologue_this_id,
arm_prologue_prev_register,
NULL,
struct frame_unwind arm_stub_unwind = {
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
arm_stub_this_id,
arm_prologue_prev_register,
NULL,
/* Walk through the list of args and determine how large a temporary
stack is required. Need to take care here as structs may be
- passed on the stack, and we have to to push them. */
+ passed on the stack, and we have to push them. */
nstack = 0;
argreg = ARM_A1_REGNUM;
else
shift = bits (inst, 7, 11);
- res = (rm == 15
+ res = (rm == ARM_PC_REGNUM
? (pc_val + (bit (inst, 4) ? 12 : 8))
: get_frame_register_unsigned (frame, rm));
another breakpoint by our caller. */
static CORE_ADDR
-thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
+thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
/* Set a breakpoint on the following instruction. */
gdb_assert ((itstate & 0x0f) != 0);
- if (insert_bkpt)
- insert_single_step_breakpoint (gdbarch, aspace, pc);
+ arm_insert_single_step_breakpoint (gdbarch, aspace,
+ MAKE_THUMB_ADDR (pc));
cond_negated = (itstate >> 4) & 1;
/* Skip all following instructions with the same
rn = bits (inst1, 0, 3);
base = get_frame_register_unsigned (frame, rn);
- if (rn == 15)
+ if (rn == ARM_PC_REGNUM)
{
base = (base + 4) & ~(CORE_ADDR) 0x3;
if (bit (inst1, 7))
}
/* Get the raw next address. PC is the current program counter, in
- FRAME. INSERT_BKPT should be TRUE if we want a breakpoint set on
- the alternative next instruction if there are two options.
+ FRAME, which is assumed to be executing in ARM mode.
The value returned has the execution state of the next instruction
encoded in it. Use IS_THUMB_ADDR () to see whether the instruction is
address. */
static CORE_ADDR
-arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
+arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
unsigned long status;
CORE_ADDR nextpc;
- if (arm_frame_is_thumb (frame))
- return thumb_get_next_pc_raw (frame, pc, insert_bkpt);
-
pc_val = (unsigned long) pc;
this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
|| bits (this_instr, 4, 27) == 0x12fff3)
{
rn = bits (this_instr, 0, 3);
- nextpc = (rn == 15) ? pc_val + 8
- : get_frame_register_unsigned (frame, rn);
+ nextpc = ((rn == ARM_PC_REGNUM)
+ ? (pc_val + 8)
+ : get_frame_register_unsigned (frame, rn));
+
return nextpc;
}
/* Multiply into PC. */
c = (status & FLAG_C) ? 1 : 0;
rn = bits (this_instr, 16, 19);
- operand1 = (rn == 15) ? pc_val + 8
- : get_frame_register_unsigned (frame, rn);
+ operand1 = ((rn == ARM_PC_REGNUM)
+ ? (pc_val + 8)
+ : get_frame_register_unsigned (frame, rn));
if (bit (this_instr, 25))
{
/* byte write to PC */
rn = bits (this_instr, 16, 19);
- base = (rn == 15) ? pc_val + 8
- : get_frame_register_unsigned (frame, rn);
+ base = ((rn == ARM_PC_REGNUM)
+ ? (pc_val + 8)
+ : get_frame_register_unsigned (frame, rn));
+
if (bit (this_instr, 24))
{
/* pre-indexed */
return nextpc;
}
+/* Determine next PC after current instruction executes. Will call either
+ arm_get_next_pc_raw or thumb_get_next_pc_raw. Error out if infinite
+ loop is detected. */
+
CORE_ADDR
arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- CORE_ADDR nextpc =
- gdbarch_addr_bits_remove (gdbarch,
- arm_get_next_pc_raw (frame, pc, TRUE));
- if (nextpc == pc)
- error (_("Infinite loop detected"));
+ CORE_ADDR nextpc;
+
+ if (arm_frame_is_thumb (frame))
+ {
+ nextpc = thumb_get_next_pc_raw (frame, pc);
+ if (nextpc == MAKE_THUMB_ADDR (pc))
+ error (_("Infinite loop detected"));
+ }
+ else
+ {
+ nextpc = arm_get_next_pc_raw (frame, pc);
+ if (nextpc == pc)
+ error (_("Infinite loop detected"));
+ }
+
return nextpc;
}
+/* Like insert_single_step_breakpoint, but make sure we use a breakpoint
+ of the appropriate mode (as encoded in the PC value), even if this
+ differs from what would be expected according to the symbol tables. */
+
+void
+arm_insert_single_step_breakpoint (struct gdbarch *gdbarch,
+ struct address_space *aspace,
+ CORE_ADDR pc)
+{
+ struct cleanup *old_chain
+ = make_cleanup_restore_integer (&arm_override_mode);
+
+ arm_override_mode = IS_THUMB_ADDR (pc);
+ pc = gdbarch_addr_bits_remove (gdbarch, pc);
+
+ insert_single_step_breakpoint (gdbarch, aspace, pc);
+
+ do_cleanups (old_chain);
+}
+
/* single_step() is called just before we want to resume the inferior,
if we want to single-step it but there is no hardware or kernel
single-step support. We find the target of the coming instruction
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
-
- /* NOTE: This may insert the wrong breakpoint instruction when
- single-stepping over a mode-changing instruction, if the
- CPSR heuristics are used. */
-
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
- insert_single_step_breakpoint (gdbarch, aspace, next_pc);
+
+ arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
location. */
ULONGEST
-displaced_read_reg (struct regcache *regs, CORE_ADDR from, int regno)
+displaced_read_reg (struct regcache *regs, struct displaced_step_closure *dsc,
+ int regno)
{
ULONGEST ret;
+ CORE_ADDR from = dsc->insn_addr;
- if (regno == 15)
+ if (regno == ARM_PC_REGNUM)
{
+ /* Compute pipeline offset:
+ - When executing an ARM instruction, PC reads as the address of the
+ current instruction plus 8.
+ - When executing a Thumb instruction, PC reads as the address of the
+ current instruction plus 4. */
+
+ if (!dsc->is_thumb)
+ from += 8;
+ else
+ from += 4;
+
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: read pc value %.8lx\n",
- (unsigned long) from + 8);
- return (ULONGEST) from + 8; /* Pipeline offset. */
+ (unsigned long) from);
+ return (ULONGEST) from;
}
else
{
/* Write to the PC as from a branch instruction. */
static void
-branch_write_pc (struct regcache *regs, ULONGEST val)
+branch_write_pc (struct regcache *regs, struct displaced_step_closure *dsc,
+ ULONGEST val)
{
- if (displaced_in_arm_mode (regs))
+ if (!dsc->is_thumb)
/* Note: If bits 0/1 are set, this branch would be unpredictable for
architecture versions < 6. */
regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
/* Write to the PC as if from a load instruction. */
static void
-load_write_pc (struct regcache *regs, ULONGEST val)
+load_write_pc (struct regcache *regs, struct displaced_step_closure *dsc,
+ ULONGEST val)
{
if (DISPLACED_STEPPING_ARCH_VERSION >= 5)
bx_write_pc (regs, val);
else
- branch_write_pc (regs, val);
+ branch_write_pc (regs, dsc, val);
}
/* Write to the PC as if from an ALU instruction. */
static void
-alu_write_pc (struct regcache *regs, ULONGEST val)
+alu_write_pc (struct regcache *regs, struct displaced_step_closure *dsc,
+ ULONGEST val)
{
- if (DISPLACED_STEPPING_ARCH_VERSION >= 7 && displaced_in_arm_mode (regs))
+ if (DISPLACED_STEPPING_ARCH_VERSION >= 7 && !dsc->is_thumb)
bx_write_pc (regs, val);
else
- branch_write_pc (regs, val);
+ branch_write_pc (regs, dsc, val);
}
/* Helper for writing to registers for displaced stepping. Writing to the PC
displaced_write_reg (struct regcache *regs, struct displaced_step_closure *dsc,
int regno, ULONGEST val, enum pc_write_style write_pc)
{
- if (regno == 15)
+ if (regno == ARM_PC_REGNUM)
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: writing pc %.8lx\n",
switch (write_pc)
{
case BRANCH_WRITE_PC:
- branch_write_pc (regs, val);
+ branch_write_pc (regs, dsc, val);
break;
case BX_WRITE_PC:
break;
case LOAD_WRITE_PC:
- load_write_pc (regs, val);
+ load_write_pc (regs, dsc, val);
break;
case ALU_WRITE_PC:
- alu_write_pc (regs, val);
+ alu_write_pc (regs, dsc, val);
break;
case CANNOT_WRITE_PC:
matter what address they are executed at: in those cases, use this. */
static int
-copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
- const char *iname, struct displaced_step_closure *dsc)
+arm_copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
+ const char *iname, struct displaced_step_closure *dsc)
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx, "
displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
}
-static int
-copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- struct displaced_step_closure *dsc)
+static void
+install_preload (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc, unsigned int rn)
{
- unsigned int rn = bits (insn, 16, 19);
ULONGEST rn_val;
- CORE_ADDR from = dsc->insn_addr;
-
- if (!insn_references_pc (insn, 0x000f0000ul))
- return copy_unmodified (gdbarch, insn, "preload", dsc);
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
- (unsigned long) insn);
-
/* Preload instructions:
{pli/pld} [rn, #+/-imm]
->
{pli/pld} [r0, #+/-imm]. */
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- rn_val = displaced_read_reg (regs, from, rn);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ rn_val = displaced_read_reg (regs, dsc, rn);
displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
-
dsc->u.preload.immed = 1;
- dsc->modinsn[0] = insn & 0xfff0ffff;
-
dsc->cleanup = &cleanup_preload;
-
- return 0;
}
-/* Preload instructions with register offset. */
-
static int
-copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
+arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
struct displaced_step_closure *dsc)
{
unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3);
- ULONGEST rn_val, rm_val;
- CORE_ADDR from = dsc->insn_addr;
- if (!insn_references_pc (insn, 0x000f000ful))
- return copy_unmodified (gdbarch, insn, "preload reg", dsc);
+ if (!insn_references_pc (insn, 0x000f0000ul))
+ return arm_copy_unmodified (gdbarch, insn, "preload", dsc);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
(unsigned long) insn);
+ dsc->modinsn[0] = insn & 0xfff0ffff;
+
+ install_preload (gdbarch, regs, dsc, rn);
+
+ return 0;
+}
+
+/* Preload instructions with register offset. */
+
+static void
+install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc, unsigned int rn,
+ unsigned int rm)
+{
+ ULONGEST rn_val, rm_val;
+
/* Preload register-offset instructions:
{pli/pld} [rn, rm {, shift}]
->
{pli/pld} [r0, r1 {, shift}]. */
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- dsc->tmp[1] = displaced_read_reg (regs, from, 1);
- rn_val = displaced_read_reg (regs, from, rn);
- rm_val = displaced_read_reg (regs, from, rm);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+ rn_val = displaced_read_reg (regs, dsc, rn);
+ rm_val = displaced_read_reg (regs, dsc, rm);
displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 1, rm_val, CANNOT_WRITE_PC);
-
dsc->u.preload.immed = 0;
- dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
-
dsc->cleanup = &cleanup_preload;
+}
+
+static int
+arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
+{
+ unsigned int rn = bits (insn, 16, 19);
+ unsigned int rm = bits (insn, 0, 3);
+
+
+ if (!insn_references_pc (insn, 0x000f000ful))
+ return arm_copy_unmodified (gdbarch, insn, "preload reg", dsc);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
+ (unsigned long) insn);
+ dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
+
+ install_preload_reg (gdbarch, regs, dsc, rn, rm);
return 0;
}
struct regcache *regs,
struct displaced_step_closure *dsc)
{
- ULONGEST rn_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+ ULONGEST rn_val = displaced_read_reg (regs, dsc, 0);
displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, dsc->u.ldst.rn, rn_val, LOAD_WRITE_PC);
}
-static int
-copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+static void
+install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc,
+ int writeback, unsigned int rn)
{
- unsigned int rn = bits (insn, 16, 19);
ULONGEST rn_val;
- CORE_ADDR from = dsc->insn_addr;
-
- if (!insn_references_pc (insn, 0x000f0000ul))
- return copy_unmodified (gdbarch, insn, "copro load/store", dsc);
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor "
- "load/store insn %.8lx\n", (unsigned long) insn);
/* Coprocessor load/store instructions:
ldc/ldc2 are handled identically. */
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- rn_val = displaced_read_reg (regs, from, rn);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ rn_val = displaced_read_reg (regs, dsc, rn);
displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
- dsc->u.ldst.writeback = bit (insn, 25);
+ dsc->u.ldst.writeback = writeback;
dsc->u.ldst.rn = rn;
+ dsc->cleanup = &cleanup_copro_load_store;
+}
+
+static int
+arm_copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
+{
+ unsigned int rn = bits (insn, 16, 19);
+
+ if (!insn_references_pc (insn, 0x000f0000ul))
+ return arm_copy_unmodified (gdbarch, insn, "copro load/store", dsc);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor "
+ "load/store insn %.8lx\n", (unsigned long) insn);
+
dsc->modinsn[0] = insn & 0xfff0ffff;
- dsc->cleanup = &cleanup_copro_load_store;
+ install_copro_load_store (gdbarch, regs, dsc, bit (insn, 25), rn);
return 0;
}
cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
- ULONGEST from = dsc->insn_addr;
- uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+ uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
int branch_taken = condition_true (dsc->u.branch.cond, status);
enum pc_write_style write_pc = dsc->u.branch.exchange
? BX_WRITE_PC : BRANCH_WRITE_PC;
if (dsc->u.branch.link)
{
- ULONGEST pc = displaced_read_reg (regs, from, 15);
- displaced_write_reg (regs, dsc, 14, pc - 4, CANNOT_WRITE_PC);
+ /* The value of LR should be the next insn of current one. In order
+ not to confuse logic hanlding later insn `bx lr', if current insn mode
+ is Thumb, the bit 0 of LR value should be set to 1. */
+ ULONGEST next_insn_addr = dsc->insn_addr + dsc->insn_size;
+
+ if (dsc->is_thumb)
+ next_insn_addr |= 0x1;
+
+ displaced_write_reg (regs, dsc, ARM_LR_REGNUM, next_insn_addr,
+ CANNOT_WRITE_PC);
}
- displaced_write_reg (regs, dsc, 15, dsc->u.branch.dest, write_pc);
+ displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->u.branch.dest, write_pc);
}
/* Copy B/BL/BLX instructions with immediate destinations. */
+static void
+install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc,
+ unsigned int cond, int exchange, int link, long offset)
+{
+ /* Implement "BL<cond> <label>" as:
+
+ Preparation: cond <- instruction condition
+ Insn: mov r0, r0 (nop)
+ Cleanup: if (condition true) { r14 <- pc; pc <- label }.
+
+ B<cond> similar, but don't set r14 in cleanup. */
+
+ dsc->u.branch.cond = cond;
+ dsc->u.branch.link = link;
+ dsc->u.branch.exchange = exchange;
+
+ if (dsc->is_thumb)
+ dsc->u.branch.dest = dsc->insn_addr + 4 + offset;
+ else
+ dsc->u.branch.dest = dsc->insn_addr + 8 + offset;
+
+ dsc->cleanup = &cleanup_branch;
+}
static int
-copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int cond = bits (insn, 28, 31);
int exchange = (cond == 0xf);
int link = exchange || bit (insn, 24);
- CORE_ADDR from = dsc->insn_addr;
long offset;
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying %s immediate insn "
"%.8lx\n", (exchange) ? "blx" : (link) ? "bl" : "b",
(unsigned long) insn);
-
- /* Implement "BL<cond> <label>" as:
-
- Preparation: cond <- instruction condition
- Insn: mov r0, r0 (nop)
- Cleanup: if (condition true) { r14 <- pc; pc <- label }.
-
- B<cond> similar, but don't set r14 in cleanup. */
-
if (exchange)
/* For BLX, set bit 0 of the destination. The cleanup_branch function will
then arrange the switch into Thumb mode. */
if (bit (offset, 25))
offset = offset | ~0x3ffffff;
- dsc->u.branch.cond = cond;
- dsc->u.branch.link = link;
- dsc->u.branch.exchange = exchange;
- dsc->u.branch.dest = from + 8 + offset;
-
dsc->modinsn[0] = ARM_NOP;
- dsc->cleanup = &cleanup_branch;
-
+ install_b_bl_blx (gdbarch, regs, dsc, cond, exchange, link, offset);
return 0;
}
/* Copy BX/BLX with register-specified destinations. */
-static int
-copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs, struct displaced_step_closure *dsc)
+static void
+install_bx_blx_reg (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc, int link,
+ unsigned int cond, unsigned int rm)
{
- unsigned int cond = bits (insn, 28, 31);
- /* BX: x12xxx1x
- BLX: x12xxx3x. */
- int link = bit (insn, 5);
- unsigned int rm = bits (insn, 0, 3);
- CORE_ADDR from = dsc->insn_addr;
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying %s register insn "
- "%.8lx\n", (link) ? "blx" : "bx",
- (unsigned long) insn);
-
/* Implement {BX,BLX}<cond> <reg>" as:
Preparation: cond <- instruction condition
Don't set r14 in cleanup for BX. */
- dsc->u.branch.dest = displaced_read_reg (regs, from, rm);
+ dsc->u.branch.dest = displaced_read_reg (regs, dsc, rm);
dsc->u.branch.cond = cond;
dsc->u.branch.link = link;
- dsc->u.branch.exchange = 1;
- dsc->modinsn[0] = ARM_NOP;
+ dsc->u.branch.exchange = 1;
dsc->cleanup = &cleanup_branch;
+}
+
+static int
+arm_copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs, struct displaced_step_closure *dsc)
+{
+ unsigned int cond = bits (insn, 28, 31);
+ /* BX: x12xxx1x
+ BLX: x12xxx3x. */
+ int link = bit (insn, 5);
+ unsigned int rm = bits (insn, 0, 3);
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx",
+ (unsigned long) insn);
+
+ dsc->modinsn[0] = ARM_NOP;
+
+ install_bx_blx_reg (gdbarch, regs, dsc, link, cond, rm);
return 0;
}
cleanup_alu_imm (struct gdbarch *gdbarch,
struct regcache *regs, struct displaced_step_closure *dsc)
{
- ULONGEST rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+ ULONGEST rd_val = displaced_read_reg (regs, dsc, 0);
displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
}
static int
-copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
unsigned int rn = bits (insn, 16, 19);
unsigned int rd = bits (insn, 12, 15);
unsigned int op = bits (insn, 21, 24);
int is_mov = (op == 0xd);
ULONGEST rd_val, rn_val;
- CORE_ADDR from = dsc->insn_addr;
if (!insn_references_pc (insn, 0x000ff000ul))
- return copy_unmodified (gdbarch, insn, "ALU immediate", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "ALU immediate", dsc);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying immediate %s insn "
Cleanup: rd <- r0; r0 <- tmp1; r1 <- tmp2
*/
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- dsc->tmp[1] = displaced_read_reg (regs, from, 1);
- rn_val = displaced_read_reg (regs, from, rn);
- rd_val = displaced_read_reg (regs, from, rd);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+ rn_val = displaced_read_reg (regs, dsc, rn);
+ rd_val = displaced_read_reg (regs, dsc, rd);
displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
dsc->rd = rd;
ULONGEST rd_val;
int i;
- rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+ rd_val = displaced_read_reg (regs, dsc, 0);
for (i = 0; i < 3; i++)
displaced_write_reg (regs, dsc, i, dsc->tmp[i], CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
}
-static int
-copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- struct displaced_step_closure *dsc)
+static void
+install_alu_reg (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc,
+ unsigned int rd, unsigned int rn, unsigned int rm)
{
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3);
- unsigned int rd = bits (insn, 12, 15);
- unsigned int op = bits (insn, 21, 24);
- int is_mov = (op == 0xd);
ULONGEST rd_val, rn_val, rm_val;
- CORE_ADDR from = dsc->insn_addr;
-
- if (!insn_references_pc (insn, 0x000ff00ful))
- return copy_unmodified (gdbarch, insn, "ALU reg", dsc);
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.8lx\n",
- is_mov ? "move" : "ALU", (unsigned long) insn);
/* Instruction is of form:
Cleanup: rd <- r0; r0, r1, r2 <- tmp1, tmp2, tmp3
*/
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- dsc->tmp[1] = displaced_read_reg (regs, from, 1);
- dsc->tmp[2] = displaced_read_reg (regs, from, 2);
- rd_val = displaced_read_reg (regs, from, rd);
- rn_val = displaced_read_reg (regs, from, rn);
- rm_val = displaced_read_reg (regs, from, rm);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+ dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
+ rd_val = displaced_read_reg (regs, dsc, rd);
+ rn_val = displaced_read_reg (regs, dsc, rn);
+ rm_val = displaced_read_reg (regs, dsc, rm);
displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 2, rm_val, CANNOT_WRITE_PC);
dsc->rd = rd;
+ dsc->cleanup = &cleanup_alu_reg;
+}
+
+static int
+arm_copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
+ struct displaced_step_closure *dsc)
+{
+ unsigned int op = bits (insn, 21, 24);
+ int is_mov = (op == 0xd);
+
+ if (!insn_references_pc (insn, 0x000ff00ful))
+ return arm_copy_unmodified (gdbarch, insn, "ALU reg", dsc);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.8lx\n",
+ is_mov ? "move" : "ALU", (unsigned long) insn);
+
if (is_mov)
dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x2;
else
dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x10002;
- dsc->cleanup = &cleanup_alu_reg;
-
+ install_alu_reg (gdbarch, regs, dsc, bits (insn, 12, 15), bits (insn, 16, 19),
+ bits (insn, 0, 3));
return 0;
}
struct regcache *regs,
struct displaced_step_closure *dsc)
{
- ULONGEST rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+ ULONGEST rd_val = displaced_read_reg (regs, dsc, 0);
int i;
for (i = 0; i < 4; i++)
displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
}
-static int
-copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+static void
+install_alu_shifted_reg (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc,
+ unsigned int rd, unsigned int rn, unsigned int rm,
+ unsigned rs)
{
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3);
- unsigned int rd = bits (insn, 12, 15);
- unsigned int rs = bits (insn, 8, 11);
- unsigned int op = bits (insn, 21, 24);
- int is_mov = (op == 0xd), i;
+ int i;
ULONGEST rd_val, rn_val, rm_val, rs_val;
- CORE_ADDR from = dsc->insn_addr;
-
- if (!insn_references_pc (insn, 0x000fff0ful))
- return copy_unmodified (gdbarch, insn, "ALU shifted reg", dsc);
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying shifted reg %s insn "
- "%.8lx\n", is_mov ? "move" : "ALU",
- (unsigned long) insn);
/* Instruction is of form:
*/
for (i = 0; i < 4; i++)
- dsc->tmp[i] = displaced_read_reg (regs, from, i);
+ dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
- rd_val = displaced_read_reg (regs, from, rd);
- rn_val = displaced_read_reg (regs, from, rn);
- rm_val = displaced_read_reg (regs, from, rm);
- rs_val = displaced_read_reg (regs, from, rs);
+ rd_val = displaced_read_reg (regs, dsc, rd);
+ rn_val = displaced_read_reg (regs, dsc, rn);
+ rm_val = displaced_read_reg (regs, dsc, rm);
+ rs_val = displaced_read_reg (regs, dsc, rs);
displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 2, rm_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 3, rs_val, CANNOT_WRITE_PC);
dsc->rd = rd;
+ dsc->cleanup = &cleanup_alu_shifted_reg;
+}
+
+static int
+arm_copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
+{
+ unsigned int op = bits (insn, 21, 24);
+ int is_mov = (op == 0xd);
+ unsigned int rd, rn, rm, rs;
+
+ if (!insn_references_pc (insn, 0x000fff0ful))
+ return arm_copy_unmodified (gdbarch, insn, "ALU shifted reg", dsc);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying shifted reg %s insn "
+ "%.8lx\n", is_mov ? "move" : "ALU",
+ (unsigned long) insn);
+
+ rn = bits (insn, 16, 19);
+ rm = bits (insn, 0, 3);
+ rs = bits (insn, 8, 11);
+ rd = bits (insn, 12, 15);
if (is_mov)
dsc->modinsn[0] = (insn & 0xfff000f0) | 0x302;
else
dsc->modinsn[0] = (insn & 0xfff000f0) | 0x10302;
- dsc->cleanup = &cleanup_alu_shifted_reg;
+ install_alu_shifted_reg (gdbarch, regs, dsc, rd, rn, rm, rs);
return 0;
}
struct displaced_step_closure *dsc)
{
ULONGEST rt_val, rt_val2 = 0, rn_val;
- CORE_ADDR from = dsc->insn_addr;
- rt_val = displaced_read_reg (regs, from, 0);
+ rt_val = displaced_read_reg (regs, dsc, 0);
if (dsc->u.ldst.xfersize == 8)
- rt_val2 = displaced_read_reg (regs, from, 1);
- rn_val = displaced_read_reg (regs, from, 2);
+ rt_val2 = displaced_read_reg (regs, dsc, 1);
+ rn_val = displaced_read_reg (regs, dsc, 2);
displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
if (dsc->u.ldst.xfersize > 4)
cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
- CORE_ADDR from = dsc->insn_addr;
- ULONGEST rn_val = displaced_read_reg (regs, from, 2);
+ ULONGEST rn_val = displaced_read_reg (regs, dsc, 2);
displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
if (dsc->u.ldst.xfersize > 4)
transfers, which have a different encoding to byte/word transfers. */
static int
-copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
- struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
+ struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int op1 = bits (insn, 20, 24);
unsigned int op2 = bits (insn, 5, 6);
int immed = (op1 & 0x4) != 0;
int opcode;
ULONGEST rt_val, rt_val2 = 0, rn_val, rm_val = 0;
- CORE_ADDR from = dsc->insn_addr;
if (!insn_references_pc (insn, 0x000ff00ful))
- return copy_unmodified (gdbarch, insn, "extra load/store", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "extra load/store", dsc);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying %sextra load/store "
internal_error (__FILE__, __LINE__,
_("copy_extra_ld_st: instruction decode error"));
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- dsc->tmp[1] = displaced_read_reg (regs, from, 1);
- dsc->tmp[2] = displaced_read_reg (regs, from, 2);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+ dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
if (!immed)
- dsc->tmp[3] = displaced_read_reg (regs, from, 3);
+ dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
- rt_val = displaced_read_reg (regs, from, rt);
+ rt_val = displaced_read_reg (regs, dsc, rt);
if (bytesize[opcode] == 8)
- rt_val2 = displaced_read_reg (regs, from, rt + 1);
- rn_val = displaced_read_reg (regs, from, rn);
+ rt_val2 = displaced_read_reg (regs, dsc, rt + 1);
+ rn_val = displaced_read_reg (regs, dsc, rn);
if (!immed)
- rm_val = displaced_read_reg (regs, from, rm);
+ rm_val = displaced_read_reg (regs, dsc, rm);
displaced_write_reg (regs, dsc, 0, rt_val, CANNOT_WRITE_PC);
if (bytesize[opcode] == 8)
/* Copy byte/word loads and stores. */
-static int
-copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc, int load, int byte,
- int usermode)
+static void
+install_ldr_str_ldrb_strb (struct gdbarch *gdbarch, struct regcache *regs,
+ struct displaced_step_closure *dsc, int load,
+ int immed, int writeback, int byte, int usermode,
+ int rt, int rm, int rn)
{
- int immed = !bit (insn, 25);
- unsigned int rt = bits (insn, 12, 15);
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3); /* Only valid if !immed. */
ULONGEST rt_val, rn_val, rm_val = 0;
- CORE_ADDR from = dsc->insn_addr;
-
- if (!insn_references_pc (insn, 0x000ff00ful))
- return copy_unmodified (gdbarch, insn, "load/store", dsc);
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying %s%s insn %.8lx\n",
- load ? (byte ? "ldrb" : "ldr")
- : (byte ? "strb" : "str"), usermode ? "t" : "",
- (unsigned long) insn);
- dsc->tmp[0] = displaced_read_reg (regs, from, 0);
- dsc->tmp[2] = displaced_read_reg (regs, from, 2);
+ dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+ dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
if (!immed)
- dsc->tmp[3] = displaced_read_reg (regs, from, 3);
+ dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
if (!load)
- dsc->tmp[4] = displaced_read_reg (regs, from, 4);
+ dsc->tmp[4] = displaced_read_reg (regs, dsc, 4);
- rt_val = displaced_read_reg (regs, from, rt);
- rn_val = displaced_read_reg (regs, from, rn);
+ rt_val = displaced_read_reg (regs, dsc, rt);
+ rn_val = displaced_read_reg (regs, dsc, rn);
if (!immed)
- rm_val = displaced_read_reg (regs, from, rm);
+ rm_val = displaced_read_reg (regs, dsc, rm);
displaced_write_reg (regs, dsc, 0, rt_val, CANNOT_WRITE_PC);
displaced_write_reg (regs, dsc, 2, rn_val, CANNOT_WRITE_PC);
if (!immed)
displaced_write_reg (regs, dsc, 3, rm_val, CANNOT_WRITE_PC);
-
dsc->rd = rt;
dsc->u.ldst.xfersize = byte ? 1 : 4;
dsc->u.ldst.rn = rn;
dsc->u.ldst.immed = immed;
- dsc->u.ldst.writeback = bit (insn, 24) == 0 || bit (insn, 21) != 0;
+ dsc->u.ldst.writeback = writeback;
/* To write PC we can do:
- scratch+0: str pc, temp (*temp = scratch + 8 + offset)
- scratch+4: ldr r4, temp
- scratch+8: sub r4, r4, pc (r4 = scratch + 8 + offset - scratch - 8 - 8)
- scratch+12: add r4, r4, #8 (r4 = offset)
- scratch+16: add r0, r0, r4
- scratch+20: str r0, [r2, #imm] (or str r0, [r2, r3])
- scratch+24: <temp>
+ Before this sequence of instructions:
+ r0 is the PC value got from displaced_read_reg, so r0 = from + 8;
+ r2 is the Rn value got from dispalced_read_reg.
+
+ Insn1: push {pc} Write address of STR instruction + offset on stack
+ Insn2: pop {r4} Read it back from stack, r4 = addr(Insn1) + offset
+ Insn3: sub r4, r4, pc r4 = addr(Insn1) + offset - pc
+ = addr(Insn1) + offset - addr(Insn3) - 8
+ = offset - 16
+ Insn4: add r4, r4, #8 r4 = offset - 8
+ Insn5: add r0, r0, r4 r0 = from + 8 + offset - 8
+ = from + offset
+ Insn6: str r0, [r2, #imm] (or str r0, [r2, r3])
Otherwise we don't know what value to write for PC, since the offset is
- architecture-dependent (sometimes PC+8, sometimes PC+12). */
+ architecture-dependent (sometimes PC+8, sometimes PC+12). More details
+ of this can be found in Section "Saving from r15" in
+ http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204g/Cihbjifh.html */
+
+ dsc->cleanup = load ? &cleanup_load : &cleanup_store;
+}
+
+static int
+arm_copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc,
+ int load, int byte, int usermode)
+{
+ int immed = !bit (insn, 25);
+ int writeback = (bit (insn, 24) == 0 || bit (insn, 21) != 0);
+ unsigned int rt = bits (insn, 12, 15);
+ unsigned int rn = bits (insn, 16, 19);
+ unsigned int rm = bits (insn, 0, 3); /* Only valid if !immed. */
- if (load || rt != 15)
+ if (!insn_references_pc (insn, 0x000ff00ful))
+ return arm_copy_unmodified (gdbarch, insn, "load/store", dsc);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: copying %s%s r%d [r%d] insn %.8lx\n",
+ load ? (byte ? "ldrb" : "ldr")
+ : (byte ? "strb" : "str"), usermode ? "t" : "",
+ rt, rn,
+ (unsigned long) insn);
+
+ install_ldr_str_ldrb_strb (gdbarch, regs, dsc, load, immed, writeback, byte,
+ usermode, rt, rm, rn);
+
+ if (load || rt != ARM_PC_REGNUM)
{
dsc->u.ldst.restore_r4 = 0;
{
/* We need to use r4 as scratch. Make sure it's restored afterwards. */
dsc->u.ldst.restore_r4 = 1;
-
- dsc->modinsn[0] = 0xe58ff014; /* str pc, [pc, #20]. */
- dsc->modinsn[1] = 0xe59f4010; /* ldr r4, [pc, #16]. */
+ dsc->modinsn[0] = 0xe92d8000; /* push {pc} */
+ dsc->modinsn[1] = 0xe8bd0010; /* pop {r4} */
dsc->modinsn[2] = 0xe044400f; /* sub r4, r4, pc. */
dsc->modinsn[3] = 0xe2844008; /* add r4, r4, #8. */
dsc->modinsn[4] = 0xe0800004; /* add r0, r0, r4. */
else
dsc->modinsn[5] = (insn & 0xfff00ff0) | 0x20003;
- dsc->modinsn[6] = 0x0; /* breakpoint location. */
- dsc->modinsn[7] = 0x0; /* scratch space. */
-
dsc->numinsns = 6;
}
cleanup_block_load_all (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
- ULONGEST from = dsc->insn_addr;
int inc = dsc->u.block.increment;
int bump_before = dsc->u.block.before ? (inc ? 4 : -4) : 0;
int bump_after = dsc->u.block.before ? 0 : (inc ? 4 : -4);
CORE_ADDR xfer_addr = dsc->u.block.xfer_addr;
int exception_return = dsc->u.block.load && dsc->u.block.user
&& (regmask & 0x8000) != 0;
- uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+ uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
int do_transfer = condition_true (dsc->u.block.cond, status);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
uint32_t memword;
if (inc)
- while (regno <= 15 && (regmask & (1 << regno)) == 0)
+ while (regno <= ARM_PC_REGNUM && (regmask & (1 << regno)) == 0)
regno++;
else
while (regno >= 0 && (regmask & (1 << regno)) == 0)
cleanup_block_store_pc (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
- ULONGEST from = dsc->insn_addr;
- uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+ uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
int store_executed = condition_true (dsc->u.block.cond, status);
CORE_ADDR pc_stored_at, transferred_regs = bitcount (dsc->u.block.regmask);
CORE_ADDR stm_insn_addr;
struct regcache *regs,
struct displaced_step_closure *dsc)
{
- ULONGEST from = dsc->insn_addr;
- uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+ uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
int load_executed = condition_true (dsc->u.block.cond, status), i;
- unsigned int mask = dsc->u.block.regmask, write_reg = 15;
+ unsigned int mask = dsc->u.block.regmask, write_reg = ARM_PC_REGNUM;
unsigned int regs_loaded = bitcount (mask);
unsigned int num_to_shuffle = regs_loaded, clobbered;
if (read_reg != write_reg)
{
- ULONGEST rval = displaced_read_reg (regs, from, read_reg);
+ ULONGEST rval = displaced_read_reg (regs, dsc, read_reg);
displaced_write_reg (regs, dsc, write_reg, rval, LOAD_WRITE_PC);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, _("displaced: LDM: move "
in user-level code (in particular exception return, ldm rn, {...pc}^). */
static int
-copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
int load = bit (insn, 20);
int user = bit (insn, 22);
int before = bit (insn, 24);
int writeback = bit (insn, 21);
int rn = bits (insn, 16, 19);
- CORE_ADDR from = dsc->insn_addr;
/* Block transfers which don't mention PC can be run directly
out-of-line. */
- if (rn != 15 && (insn & 0x8000) == 0)
- return copy_unmodified (gdbarch, insn, "ldm/stm", dsc);
+ if (rn != ARM_PC_REGNUM && (insn & 0x8000) == 0)
+ return arm_copy_unmodified (gdbarch, insn, "ldm/stm", dsc);
- if (rn == 15)
+ if (rn == ARM_PC_REGNUM)
{
warning (_("displaced: Unpredictable LDM or STM with "
"base register r15"));
- return copy_unmodified (gdbarch, insn, "unpredictable ldm/stm", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "unpredictable ldm/stm", dsc);
}
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying block transfer insn "
"%.8lx\n", (unsigned long) insn);
- dsc->u.block.xfer_addr = displaced_read_reg (regs, from, rn);
+ dsc->u.block.xfer_addr = displaced_read_reg (regs, dsc, rn);
dsc->u.block.rn = rn;
dsc->u.block.load = load;
unsigned int to = 0, from = 0, i, new_rn;
for (i = 0; i < num_in_list; i++)
- dsc->tmp[i] = displaced_read_reg (regs, from, i);
+ dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
/* Writeback makes things complicated. We need to avoid clobbering
the base register with one of the registers in our modified
cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
- CORE_ADDR from = dsc->insn_addr;
- CORE_ADDR resume_addr = from + 4;
+ CORE_ADDR resume_addr = dsc->insn_addr + dsc->insn_size;
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: cleanup for svc, resume at "
}
static int
-copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
- struct regcache *regs, struct displaced_step_closure *dsc)
-{
- CORE_ADDR from = dsc->insn_addr;
- /* Allow OS-specific code to override SVC handling. */
- if (dsc->u.svc.copy_svc_os)
- return dsc->u.svc.copy_svc_os (gdbarch, insn, to, regs, dsc);
+arm_copy_svc (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs, struct displaced_step_closure *dsc)
+{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying svc insn %.8lx\n",
dsc->modinsn[0] = insn;
- dsc->cleanup = &cleanup_svc;
/* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
instruction. */
dsc->wrote_to_pc = 1;
- return 0;
+ /* Allow OS-specific code to override SVC handling. */
+ if (dsc->u.svc.copy_svc_os)
+ return dsc->u.svc.copy_svc_os (gdbarch, regs, dsc);
+ else
+ {
+ dsc->cleanup = &cleanup_svc;
+ return 0;
+ }
+
}
/* Copy undefined instructions. */
static int
-copy_undef (struct gdbarch *gdbarch, uint32_t insn,
- struct displaced_step_closure *dsc)
+arm_copy_undef (struct gdbarch *gdbarch, uint32_t insn,
+ struct displaced_step_closure *dsc)
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
/* Copy unpredictable instructions. */
static int
-copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
- struct displaced_step_closure *dsc)
+arm_copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
+ struct displaced_step_closure *dsc)
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copying unpredictable insn "
the presentation in the ARM ARM. */
static int
-decode_misc_memhint_neon (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_decode_misc_memhint_neon (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
unsigned int rn = bits (insn, 16, 19);
if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
- return copy_unmodified (gdbarch, insn, "cps", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "cps", dsc);
else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
- return copy_unmodified (gdbarch, insn, "setend", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "setend", dsc);
else if ((op1 & 0x60) == 0x20)
- return copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
else if ((op1 & 0x71) == 0x40)
- return copy_unmodified (gdbarch, insn, "neon elt/struct load/store", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "neon elt/struct load/store",
+ dsc);
else if ((op1 & 0x77) == 0x41)
- return copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
else if ((op1 & 0x77) == 0x45)
- return copy_preload (gdbarch, insn, regs, dsc); /* pli. */
+ return arm_copy_preload (gdbarch, insn, regs, dsc); /* pli. */
else if ((op1 & 0x77) == 0x51)
{
if (rn != 0xf)
- return copy_preload (gdbarch, insn, regs, dsc); /* pld/pldw. */
+ return arm_copy_preload (gdbarch, insn, regs, dsc); /* pld/pldw. */
else
- return copy_unpred (gdbarch, insn, dsc);
+ return arm_copy_unpred (gdbarch, insn, dsc);
}
else if ((op1 & 0x77) == 0x55)
- return copy_preload (gdbarch, insn, regs, dsc); /* pld/pldw. */
+ return arm_copy_preload (gdbarch, insn, regs, dsc); /* pld/pldw. */
else if (op1 == 0x57)
switch (op2)
{
- case 0x1: return copy_unmodified (gdbarch, insn, "clrex", dsc);
- case 0x4: return copy_unmodified (gdbarch, insn, "dsb", dsc);
- case 0x5: return copy_unmodified (gdbarch, insn, "dmb", dsc);
- case 0x6: return copy_unmodified (gdbarch, insn, "isb", dsc);
- default: return copy_unpred (gdbarch, insn, dsc);
+ case 0x1: return arm_copy_unmodified (gdbarch, insn, "clrex", dsc);
+ case 0x4: return arm_copy_unmodified (gdbarch, insn, "dsb", dsc);
+ case 0x5: return arm_copy_unmodified (gdbarch, insn, "dmb", dsc);
+ case 0x6: return arm_copy_unmodified (gdbarch, insn, "isb", dsc);
+ default: return arm_copy_unpred (gdbarch, insn, dsc);
}
else if ((op1 & 0x63) == 0x43)
- return copy_unpred (gdbarch, insn, dsc);
+ return arm_copy_unpred (gdbarch, insn, dsc);
else if ((op2 & 0x1) == 0x0)
switch (op1 & ~0x80)
{
case 0x61:
- return copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
case 0x65:
- return copy_preload_reg (gdbarch, insn, regs, dsc); /* pli reg. */
+ return arm_copy_preload_reg (gdbarch, insn, regs, dsc); /* pli reg. */
case 0x71: case 0x75:
/* pld/pldw reg. */
- return copy_preload_reg (gdbarch, insn, regs, dsc);
+ return arm_copy_preload_reg (gdbarch, insn, regs, dsc);
case 0x63: case 0x67: case 0x73: case 0x77:
- return copy_unpred (gdbarch, insn, dsc);
+ return arm_copy_unpred (gdbarch, insn, dsc);
default:
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
}
else
- return copy_undef (gdbarch, insn, dsc); /* Probably unreachable. */
+ return arm_copy_undef (gdbarch, insn, dsc); /* Probably unreachable. */
}
static int
-decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
if (bit (insn, 27) == 0)
- return decode_misc_memhint_neon (gdbarch, insn, regs, dsc);
+ return arm_decode_misc_memhint_neon (gdbarch, insn, regs, dsc);
/* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx. */
else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
{
case 0x0: case 0x2:
- return copy_unmodified (gdbarch, insn, "srs", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "srs", dsc);
case 0x1: case 0x3:
- return copy_unmodified (gdbarch, insn, "rfe", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "rfe", dsc);
case 0x4: case 0x5: case 0x6: case 0x7:
- return copy_b_bl_blx (gdbarch, insn, regs, dsc);
+ return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
case 0x8:
switch ((insn & 0xe00000) >> 21)
{
case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
/* stc/stc2. */
- return copy_copro_load_store (gdbarch, insn, regs, dsc);
+ return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
case 0x2:
- return copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
default:
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
}
case 0x9:
{
case 0x1: case 0x3:
/* ldc/ldc2 imm (undefined for rn == pc). */
- return rn_f ? copy_undef (gdbarch, insn, dsc)
- : copy_copro_load_store (gdbarch, insn, regs, dsc);
+ return rn_f ? arm_copy_undef (gdbarch, insn, dsc)
+ : arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
case 0x2:
- return copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
case 0x4: case 0x5: case 0x6: case 0x7:
/* ldc/ldc2 lit (undefined for rn != pc). */
- return rn_f ? copy_copro_load_store (gdbarch, insn, regs, dsc)
- : copy_undef (gdbarch, insn, dsc);
+ return rn_f ? arm_copy_copro_load_store (gdbarch, insn, regs, dsc)
+ : arm_copy_undef (gdbarch, insn, dsc);
default:
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
}
}
case 0xa:
- return copy_unmodified (gdbarch, insn, "stc/stc2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "stc/stc2", dsc);
case 0xb:
if (bits (insn, 16, 19) == 0xf)
/* ldc/ldc2 lit. */
- return copy_copro_load_store (gdbarch, insn, regs, dsc);
+ return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0xc:
if (bit (insn, 4))
- return copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
else
- return copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
case 0xd:
if (bit (insn, 4))
- return copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
else
- return copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
default:
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
}
}
/* Decode miscellaneous instructions in dp/misc encoding space. */
static int
-decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
unsigned int op2 = bits (insn, 4, 6);
unsigned int op = bits (insn, 21, 22);
switch (op2)
{
case 0x0:
- return copy_unmodified (gdbarch, insn, "mrs/msr", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mrs/msr", dsc);
case 0x1:
if (op == 0x1) /* bx. */
- return copy_bx_blx_reg (gdbarch, insn, regs, dsc);
+ return arm_copy_bx_blx_reg (gdbarch, insn, regs, dsc);
else if (op == 0x3)
- return copy_unmodified (gdbarch, insn, "clz", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "clz", dsc);
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0x2:
if (op == 0x1)
/* Not really supported. */
- return copy_unmodified (gdbarch, insn, "bxj", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "bxj", dsc);
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0x3:
if (op == 0x1)
- return copy_bx_blx_reg (gdbarch, insn,
+ return arm_copy_bx_blx_reg (gdbarch, insn,
regs, dsc); /* blx register. */
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0x5:
- return copy_unmodified (gdbarch, insn, "saturating add/sub", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "saturating add/sub", dsc);
case 0x7:
if (op == 0x1)
- return copy_unmodified (gdbarch, insn, "bkpt", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "bkpt", dsc);
else if (op == 0x3)
/* Not really supported. */
- return copy_unmodified (gdbarch, insn, "smc", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "smc", dsc);
default:
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
}
}
static int
-decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
if (bit (insn, 25))
switch (bits (insn, 20, 24))
{
case 0x10:
- return copy_unmodified (gdbarch, insn, "movw", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "movw", dsc);
case 0x14:
- return copy_unmodified (gdbarch, insn, "movt", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "movt", dsc);
case 0x12: case 0x16:
- return copy_unmodified (gdbarch, insn, "msr imm", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "msr imm", dsc);
default:
- return copy_alu_imm (gdbarch, insn, regs, dsc);
+ return arm_copy_alu_imm (gdbarch, insn, regs, dsc);
}
else
{
uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
- return copy_alu_reg (gdbarch, insn, regs, dsc);
+ return arm_copy_alu_reg (gdbarch, insn, regs, dsc);
else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
- return copy_alu_shifted_reg (gdbarch, insn, regs, dsc);
+ return arm_copy_alu_shifted_reg (gdbarch, insn, regs, dsc);
else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
- return decode_miscellaneous (gdbarch, insn, regs, dsc);
+ return arm_decode_miscellaneous (gdbarch, insn, regs, dsc);
else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
- return copy_unmodified (gdbarch, insn, "halfword mul/mla", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "halfword mul/mla", dsc);
else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
- return copy_unmodified (gdbarch, insn, "mul/mla", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mul/mla", dsc);
else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
- return copy_unmodified (gdbarch, insn, "synch", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "synch", dsc);
else if (op2 == 0xb || (op2 & 0xd) == 0xd)
/* 2nd arg means "unpriveleged". */
- return copy_extra_ld_st (gdbarch, insn, (op1 & 0x12) == 0x02, regs,
- dsc);
+ return arm_copy_extra_ld_st (gdbarch, insn, (op1 & 0x12) == 0x02, regs,
+ dsc);
}
/* Should be unreachable. */
}
static int
-decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
int a = bit (insn, 25), b = bit (insn, 4);
uint32_t op1 = bits (insn, 20, 24);
if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
|| (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 0);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 0);
else if ((!a && (op1 & 0x17) == 0x02)
|| (a && (op1 & 0x17) == 0x02 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 1);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 1);
else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
|| (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 0);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 0);
else if ((!a && (op1 & 0x17) == 0x03)
|| (a && (op1 & 0x17) == 0x03 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 1);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 1);
else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
|| (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 0);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 0);
else if ((!a && (op1 & 0x17) == 0x06)
|| (a && (op1 & 0x17) == 0x06 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 1);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 1);
else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
|| (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 0);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 0);
else if ((!a && (op1 & 0x17) == 0x07)
|| (a && (op1 & 0x17) == 0x07 && !b))
- return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 1);
+ return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 1);
/* Should be unreachable. */
return 1;
}
static int
-decode_media (struct gdbarch *gdbarch, uint32_t insn,
- struct displaced_step_closure *dsc)
+arm_decode_media (struct gdbarch *gdbarch, uint32_t insn,
+ struct displaced_step_closure *dsc)
{
switch (bits (insn, 20, 24))
{
case 0x00: case 0x01: case 0x02: case 0x03:
- return copy_unmodified (gdbarch, insn, "parallel add/sub signed", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "parallel add/sub signed", dsc);
case 0x04: case 0x05: case 0x06: case 0x07:
- return copy_unmodified (gdbarch, insn, "parallel add/sub unsigned", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "parallel add/sub unsigned", dsc);
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- return copy_unmodified (gdbarch, insn,
+ return arm_copy_unmodified (gdbarch, insn,
"decode/pack/unpack/saturate/reverse", dsc);
case 0x18:
if (bits (insn, 5, 7) == 0) /* op2. */
{
if (bits (insn, 12, 15) == 0xf)
- return copy_unmodified (gdbarch, insn, "usad8", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "usad8", dsc);
else
- return copy_unmodified (gdbarch, insn, "usada8", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "usada8", dsc);
}
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0x1a: case 0x1b:
if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
- return copy_unmodified (gdbarch, insn, "sbfx", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "sbfx", dsc);
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0x1c: case 0x1d:
if (bits (insn, 5, 6) == 0x0) /* op2[1:0]. */
{
if (bits (insn, 0, 3) == 0xf)
- return copy_unmodified (gdbarch, insn, "bfc", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "bfc", dsc);
else
- return copy_unmodified (gdbarch, insn, "bfi", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "bfi", dsc);
}
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
case 0x1e: case 0x1f:
if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
- return copy_unmodified (gdbarch, insn, "ubfx", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "ubfx", dsc);
else
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
}
/* Should be unreachable. */
}
static int
-decode_b_bl_ldmstm (struct gdbarch *gdbarch, int32_t insn,
- struct regcache *regs, struct displaced_step_closure *dsc)
+arm_decode_b_bl_ldmstm (struct gdbarch *gdbarch, int32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
if (bit (insn, 25))
- return copy_b_bl_blx (gdbarch, insn, regs, dsc);
+ return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
else
- return copy_block_xfer (gdbarch, insn, regs, dsc);
+ return arm_copy_block_xfer (gdbarch, insn, regs, dsc);
}
static int
-decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- struct displaced_step_closure *dsc)
+arm_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
+ struct regcache *regs,
+ struct displaced_step_closure *dsc)
{
unsigned int opcode = bits (insn, 20, 24);
switch (opcode)
{
case 0x04: case 0x05: /* VFP/Neon mrrc/mcrr. */
- return copy_unmodified (gdbarch, insn, "vfp/neon mrrc/mcrr", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "vfp/neon mrrc/mcrr", dsc);
case 0x08: case 0x0a: case 0x0c: case 0x0e:
case 0x12: case 0x16:
- return copy_unmodified (gdbarch, insn, "vfp/neon vstm/vpush", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "vfp/neon vstm/vpush", dsc);
case 0x09: case 0x0b: case 0x0d: case 0x0f:
case 0x13: case 0x17:
- return copy_unmodified (gdbarch, insn, "vfp/neon vldm/vpop", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "vfp/neon vldm/vpop", dsc);
case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */
case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */
/* Note: no writeback for these instructions. Bit 25 will always be
zero though (via caller), so the following works OK. */
- return copy_copro_load_store (gdbarch, insn, regs, dsc);
+ return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
}
/* Should be unreachable. */
}
static int
-decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
- struct regcache *regs, struct displaced_step_closure *dsc)
+arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
+ struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int op1 = bits (insn, 20, 25);
int op = bit (insn, 4);
unsigned int rn = bits (insn, 16, 19);
if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
- return decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
+ return arm_decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
&& (coproc & 0xe) != 0xa)
/* stc/stc2. */
- return copy_copro_load_store (gdbarch, insn, regs, dsc);
+ return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
&& (coproc & 0xe) != 0xa)
/* ldc/ldc2 imm/lit. */
- return copy_copro_load_store (gdbarch, insn, regs, dsc);
+ return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
else if ((op1 & 0x3e) == 0x00)
- return copy_undef (gdbarch, insn, dsc);
+ return arm_copy_undef (gdbarch, insn, dsc);
else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
- return copy_unmodified (gdbarch, insn, "neon 64bit xfer", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "neon 64bit xfer", dsc);
else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
- return copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
- return copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
else if ((op1 & 0x30) == 0x20 && !op)
{
if ((coproc & 0xe) == 0xa)
- return copy_unmodified (gdbarch, insn, "vfp dataproc", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "vfp dataproc", dsc);
else
- return copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
}
else if ((op1 & 0x30) == 0x20 && op)
- return copy_unmodified (gdbarch, insn, "neon 8/16/32 bit xfer", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "neon 8/16/32 bit xfer", dsc);
else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
- return copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
- return copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
+ return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
else if ((op1 & 0x30) == 0x30)
- return copy_svc (gdbarch, insn, to, regs, dsc);
+ return arm_copy_svc (gdbarch, insn, regs, dsc);
else
- return copy_undef (gdbarch, insn, dsc); /* Possibly unreachable. */
+ return arm_copy_undef (gdbarch, insn, dsc); /* Possibly unreachable. */
+}
+
+static void
+thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
+ CORE_ADDR to, struct regcache *regs,
+ struct displaced_step_closure *dsc)
+{
+ error (_("Displaced stepping is only supported in ARM mode"));
}
void
-arm_process_displaced_insn (struct gdbarch *gdbarch, uint32_t insn,
- CORE_ADDR from, CORE_ADDR to,
- struct regcache *regs,
+arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
+ CORE_ADDR to, struct regcache *regs,
struct displaced_step_closure *dsc)
{
int err = 0;
-
- if (!displaced_in_arm_mode (regs))
- error (_("Displaced stepping is only supported in ARM mode"));
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ uint32_t insn;
/* Most displaced instructions use a 1-instruction scratch space, so set this
here and override below if/when necessary. */
dsc->cleanup = NULL;
dsc->wrote_to_pc = 0;
+ if (!displaced_in_arm_mode (regs))
+ return thumb_process_displaced_insn (gdbarch, from, to, regs, dsc);
+
+ dsc->is_thumb = 0;
+ dsc->insn_size = 4;
+ insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: stepping insn %.8lx "
+ "at %.8lx\n", (unsigned long) insn,
+ (unsigned long) from);
+
if ((insn & 0xf0000000) == 0xf0000000)
- err = decode_unconditional (gdbarch, insn, regs, dsc);
+ err = arm_decode_unconditional (gdbarch, insn, regs, dsc);
else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
{
case 0x0: case 0x1: case 0x2: case 0x3:
- err = decode_dp_misc (gdbarch, insn, regs, dsc);
+ err = arm_decode_dp_misc (gdbarch, insn, regs, dsc);
break;
case 0x4: case 0x5: case 0x6:
- err = decode_ld_st_word_ubyte (gdbarch, insn, regs, dsc);
+ err = arm_decode_ld_st_word_ubyte (gdbarch, insn, regs, dsc);
break;
case 0x7:
- err = decode_media (gdbarch, insn, dsc);
+ err = arm_decode_media (gdbarch, insn, dsc);
break;
case 0x8: case 0x9: case 0xa: case 0xb:
- err = decode_b_bl_ldmstm (gdbarch, insn, regs, dsc);
+ err = arm_decode_b_bl_ldmstm (gdbarch, insn, regs, dsc);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
- err = decode_svc_copro (gdbarch, insn, to, regs, dsc);
+ err = arm_decode_svc_copro (gdbarch, insn, to, regs, dsc);
break;
}
CORE_ADDR to, struct displaced_step_closure *dsc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- unsigned int i;
+ unsigned int i, len, offset;
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ int size = dsc->is_thumb? 2 : 4;
+ const unsigned char *bkp_insn;
+ offset = 0;
/* Poke modified instruction(s). */
for (i = 0; i < dsc->numinsns; i++)
{
if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: writing insn %.8lx at "
- "%.8lx\n", (unsigned long) dsc->modinsn[i],
- (unsigned long) to + i * 4);
- write_memory_unsigned_integer (to + i * 4, 4, byte_order_for_code,
+ {
+ fprintf_unfiltered (gdb_stdlog, "displaced: writing insn ");
+ if (size == 4)
+ fprintf_unfiltered (gdb_stdlog, "%.8lx",
+ dsc->modinsn[i]);
+ else if (size == 2)
+ fprintf_unfiltered (gdb_stdlog, "%.4x",
+ (unsigned short)dsc->modinsn[i]);
+
+ fprintf_unfiltered (gdb_stdlog, " at %.8lx\n",
+ (unsigned long) to + offset);
+
+ }
+ write_memory_unsigned_integer (to + offset, size,
+ byte_order_for_code,
dsc->modinsn[i]);
+ offset += size;
+ }
+
+ /* Choose the correct breakpoint instruction. */
+ if (dsc->is_thumb)
+ {
+ bkp_insn = tdep->thumb_breakpoint;
+ len = tdep->thumb_breakpoint_size;
+ }
+ else
+ {
+ bkp_insn = tdep->arm_breakpoint;
+ len = tdep->arm_breakpoint_size;
}
/* Put breakpoint afterwards. */
- write_memory (to + dsc->numinsns * 4, tdep->arm_breakpoint,
- tdep->arm_breakpoint_size);
+ write_memory (to + offset, bkp_insn, len);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ",
{
struct displaced_step_closure *dsc
= xmalloc (sizeof (struct displaced_step_closure));
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- uint32_t insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
-
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: stepping insn %.8lx "
- "at %.8lx\n", (unsigned long) insn,
- (unsigned long) from);
-
- arm_process_displaced_insn (gdbarch, insn, from, to, regs, dsc);
+ arm_process_displaced_insn (gdbarch, from, to, regs, dsc);
arm_displaced_init_closure (gdbarch, from, to, dsc);
return dsc;
dsc->cleanup (gdbarch, regs, dsc);
if (!dsc->wrote_to_pc)
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, dsc->insn_addr + 4);
+ regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
+ dsc->insn_addr + dsc->insn_size);
+
}
#include "bfd-in2.h"
|| TYPE_CODE (type) == TYPE_CODE_REF
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
{
- /* If the the type is a plain integer, then the access is
- straight-forward. Otherwise we have to play around a bit more. */
+ /* 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);
int regno = ARM_A1_REGNUM;
ULONGEST tmp;
static void
arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
{
- /* Thumb symbols are of type STT_LOPROC, (synonymous with
- STT_ARM_TFUNC). */
- if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info)
- == STT_LOPROC)
+ if (ARM_SYM_BRANCH_TYPE (&((elf_symbol_type *)sym)->internal_elf_sym)
+ == ST_BRANCH_TO_THUMB)
MSYMBOL_SET_SPECIAL (msym);
}
ABI, even if a NEON unit is not present. REGNUM is the index of
the quad register, in [0, 15]. */
-static void
+static enum register_status
arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, gdb_byte *buf)
{
char name_buf[4];
gdb_byte reg_buf[8];
int offset, double_regnum;
+ enum register_status status;
sprintf (name_buf, "d%d", regnum << 1);
double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
else
offset = 0;
- regcache_raw_read (regcache, double_regnum, reg_buf);
+ status = regcache_raw_read (regcache, double_regnum, reg_buf);
+ if (status != REG_VALID)
+ return status;
memcpy (buf + offset, reg_buf, 8);
offset = 8 - offset;
- regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+ status = regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+ if (status != REG_VALID)
+ return status;
memcpy (buf + offset, reg_buf, 8);
+
+ return REG_VALID;
}
-static void
+static enum register_status
arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, gdb_byte *buf)
{
if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
/* Quad-precision register. */
- arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
+ return arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
else
{
+ enum register_status status;
+
/* Single-precision register. */
gdb_assert (regnum < 32);
double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
- regcache_raw_read (regcache, double_regnum, reg_buf);
- memcpy (buf, reg_buf + offset, 4);
+ status = regcache_raw_read (regcache, double_regnum, reg_buf);
+ if (status == REG_VALID)
+ memcpy (buf, reg_buf + offset, 4);
+ return status;
}
}
if (!valid_p)
break;
}
+ if (!valid_p && i == 16)
+ valid_p = 1;
- if (!valid_p && i != 16)
+ /* Also require FPSCR. */
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ ARM_FPSCR_REGNUM, "fpscr");
+ if (!valid_p)
{
tdesc_data_cleanup (tdesc_data);
return NULL;
if (tdep->arm_abi == ARM_ABI_AUTO)
tdep->arm_abi = ARM_ABI_APCS;
+ /* Watchpoints are not steppable. */
+ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
/* We used to default to FPA for generic ARM, but almost nobody
uses that now, and we now provide a way for the user to force
the model. So default to the most useful variant. */
/* Initialize the standard target descriptions. */
initialize_tdesc_arm_with_m ();
+ initialize_tdesc_arm_with_iwmmxt ();
+ initialize_tdesc_arm_with_vfpv2 ();
+ initialize_tdesc_arm_with_vfpv3 ();
+ initialize_tdesc_arm_with_neon ();
/* Get the number of possible sets of register names defined in opcodes. */
num_disassembly_options = get_arm_regname_num_options ();