#include "record.h"
#include "record-full.h"
+#include <algorithm>
-#include "features/arm-with-m.c"
-#include "features/arm-with-m-fpa-layout.c"
-#include "features/arm-with-m-vfp-d16.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"
+#include "features/arm/arm-with-m.c"
+#include "features/arm/arm-with-m-fpa-layout.c"
+#include "features/arm/arm-with-m-vfp-d16.c"
+#include "features/arm/arm-with-iwmmxt.c"
+#include "features/arm/arm-with-vfpv2.c"
+#include "features/arm/arm-with-vfpv3.c"
+#include "features/arm/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;
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;
return 0;
}
+/* Determine if the address specified equals any of these magic return
+ values, called EXC_RETURN, defined by the ARM v6-M and v7-M
+ architectures.
+
+ From ARMv6-M Reference Manual B1.5.8
+ Table B1-5 Exception return behavior
+
+ EXC_RETURN Return To Return Stack
+ 0xFFFFFFF1 Handler mode Main
+ 0xFFFFFFF9 Thread mode Main
+ 0xFFFFFFFD Thread mode Process
+
+ From ARMv7-M Reference Manual B1.5.8
+ Table B1-8 EXC_RETURN definition of exception return behavior, no FP
+
+ EXC_RETURN Return To Return Stack
+ 0xFFFFFFF1 Handler mode Main
+ 0xFFFFFFF9 Thread mode Main
+ 0xFFFFFFFD Thread mode Process
+
+ Table B1-9 EXC_RETURN definition of exception return behavior, with
+ FP
+
+ EXC_RETURN Return To Return Stack Frame Type
+ 0xFFFFFFE1 Handler mode Main Extended
+ 0xFFFFFFE9 Thread mode Main Extended
+ 0xFFFFFFED Thread mode Process Extended
+ 0xFFFFFFF1 Handler mode Main Basic
+ 0xFFFFFFF9 Thread mode Main Basic
+ 0xFFFFFFFD Thread mode Process Basic
+
+ For more details see "B1.5.8 Exception return behavior"
+ in both ARMv6-M and ARMv7-M Architecture Reference Manuals. */
+
+static int
+arm_m_addr_is_magic (CORE_ADDR addr)
+{
+ switch (addr)
+ {
+ /* Values from Tables in B1.5.8 the EXC_RETURN definitions of
+ the exception return behavior. */
+ case 0xffffffe1:
+ case 0xffffffe9:
+ case 0xffffffed:
+ case 0xfffffff1:
+ case 0xfffffff9:
+ case 0xfffffffd:
+ /* Address is magic. */
+ return 1;
+
+ default:
+ /* Address is not magic. */
+ return 0;
+ }
+}
+
/* Remove useless bits from addresses in a running program. */
static CORE_ADDR
arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
/* On M-profile devices, do not strip the low bit from EXC_RETURN
(the magic exception return address). */
if (gdbarch_tdep (gdbarch)->is_m
- && (val & 0xfffffff0) == 0xfffffff0)
+ && arm_m_addr_is_magic (val))
return val;
if (arm_apcs_32)
function is. */
return;
- prologue_end = min (prologue_end, prev_pc);
+ prologue_end = std::min (prologue_end, prev_pc);
thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
arm_exidx_unwind_sniffer
};
+static struct arm_prologue_cache *
+arm_make_epilogue_frame_cache (struct frame_info *this_frame)
+{
+ struct arm_prologue_cache *cache;
+ int reg;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Still rely on the offset calculated from prologue. */
+ arm_scan_prologue (this_frame, cache);
+
+ /* Since we are in epilogue, the SP has been restored. */
+ cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+
+ /* Calculate actual addresses of saved registers using offsets
+ determined by arm_scan_prologue. */
+ for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->prev_sp;
+
+ return cache;
+}
+
+/* Implementation of function hook 'this_id' in
+ 'struct frame_uwnind' for epilogue unwinder. */
+
+static void
+arm_epilogue_frame_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+ CORE_ADDR pc, func;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_epilogue_frame_cache (this_frame);
+ cache = (struct arm_prologue_cache *) *this_cache;
+
+ /* Use function start address as part of the frame ID. If we cannot
+ identify the start address (due to missing symbol information),
+ fall back to just using the current PC. */
+ pc = get_frame_pc (this_frame);
+ func = get_frame_func (this_frame);
+ if (func == 0)
+ func = pc;
+
+ (*this_id) = frame_id_build (cache->prev_sp, pc);
+}
+
+/* Implementation of function hook 'prev_register' in
+ 'struct frame_uwnind' for epilogue unwinder. */
+
+static struct value *
+arm_epilogue_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ if (*this_cache == NULL)
+ *this_cache = arm_make_epilogue_frame_cache (this_frame);
+
+ return arm_prologue_prev_register (this_frame, this_cache, regnum);
+}
+
+static int arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch,
+ CORE_ADDR pc);
+static int thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch,
+ CORE_ADDR pc);
+
+/* Implementation of function hook 'sniffer' in
+ 'struct frame_uwnind' for epilogue unwinder. */
+
+static int
+arm_epilogue_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ if (frame_relative_level (this_frame) == 0)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
+
+ if (arm_frame_is_thumb (this_frame))
+ return thumb_stack_frame_destroyed_p (gdbarch, pc);
+ else
+ return arm_stack_frame_destroyed_p_1 (gdbarch, pc);
+ }
+ else
+ return 0;
+}
+
+/* Frame unwinder from epilogue. */
+
+static const struct frame_unwind arm_epilogue_frame_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ arm_epilogue_frame_this_id,
+ arm_epilogue_frame_prev_register,
+ NULL,
+ arm_epilogue_frame_sniffer,
+};
+
/* Recognize GCC's trampoline for thumb call-indirect. If we are in a
trampoline, return the target PC. Otherwise return 0.
/* No need to check is_m; this sniffer is only registered for
M-profile architectures. */
- /* Exception frames return to one of these magic PCs. Other values
- are not defined as of v7-M. See details in "B1.5.8 Exception
- return behavior" in "ARMv7-M Architecture Reference Manual". */
- if (this_pc == 0xfffffff1 || this_pc == 0xfffffff9
- || this_pc == 0xfffffffd)
- return 1;
-
- return 0;
+ /* Check if exception frame returns to a magic PC value. */
+ return arm_m_addr_is_magic (this_pc);
}
/* Frame unwinder for M-profile exceptions. */
return found_stack_adjust;
}
-/* Implement the stack_frame_destroyed_p gdbarch method. */
-
static int
-arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch, CORE_ADDR pc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned int insn;
int found_return;
CORE_ADDR func_start, func_end;
- if (arm_pc_is_thumb (gdbarch, pc))
- return thumb_stack_frame_destroyed_p (gdbarch, pc);
-
if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
return 0;
return 0;
}
+/* Implement the stack_frame_destroyed_p gdbarch method. */
+
+static int
+arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ if (arm_pc_is_thumb (gdbarch, pc))
+ return thumb_stack_frame_destroyed_p (gdbarch, pc);
+ else
+ return arm_stack_frame_destroyed_p_1 (gdbarch, pc);
+}
/* When arguments must be pushed onto the stack, they go on in reverse
order. The code below implements a FILO (stack) to do this. */
int i;
for (i = 0; i < TYPE_NFIELDS (t); i++)
{
- int sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i),
- base_type);
+ int sub_count = 0;
+
+ if (!field_is_static (&TYPE_FIELD (t, i)))
+ sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i),
+ base_type);
if (sub_count == -1)
return -1;
count += sub_count;
&d, dbl);
}
-/* 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);
-}
-
/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
the buffer to be NEW_LEN bytes ending at ENDADDR. Return
NULL if an error occurs. BUF is freed. */
footwork to distinguish a real IT instruction from the second
half of a 32-bit instruction, but there is no need for that if
there's no candidate. */
- buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
+ buf_len = std::min (bpaddr - boundary, (CORE_ADDR) MAX_IT_BLOCK_PREFIX);
if (buf_len == 0)
/* No room for an IT instruction. */
return bpaddr;
next_pcs = arm_get_next_pcs (&next_pcs_ctx);
for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
- arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+ {
+ pc = gdbarch_addr_bits_remove (gdbarch, pc);
+ insert_single_step_breakpoint (gdbarch, aspace, pc);
+ }
do_cleanups (old_chain);
}
static int
-arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
+arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn,
struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int op1 = bits (insn, 20, 25);
static void
thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
- CORE_ADDR to, struct regcache *regs,
+ struct regcache *regs,
struct displaced_step_closure *dsc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
dsc->wrote_to_pc = 0;
if (!displaced_in_arm_mode (regs))
- return thumb_process_displaced_insn (gdbarch, from, to, regs, dsc);
+ return thumb_process_displaced_insn (gdbarch, from, regs, dsc);
dsc->is_thumb = 0;
dsc->insn_size = 4;
break;
case 0xc: case 0xd: case 0xe: case 0xf:
- err = arm_decode_svc_copro (gdbarch, insn, to, regs, dsc);
+ err = arm_decode_svc_copro (gdbarch, insn, regs, dsc);
break;
}
static const gdb_byte arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
static const gdb_byte arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
-/* Determine the type and size of breakpoint to insert at PCPTR. Uses
- the program counter value to determine whether a 16-bit or 32-bit
- breakpoint should be used. It returns a pointer to a string of
- bytes that encode a breakpoint instruction, stores the length of
- the string to *lenptr, and adjusts the program counter (if
- necessary) to point to the actual memory location where the
- breakpoint should be inserted. */
+/* Implement the breakpoint_kind_from_pc gdbarch method. */
-static const unsigned char *
-arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
+static int
+arm_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
if (tdep->thumb2_breakpoint != NULL)
{
gdb_byte buf[2];
+
if (target_read_memory (*pcptr, buf, 2) == 0)
{
unsigned short inst1;
+
inst1 = extract_unsigned_integer (buf, 2, byte_order_for_code);
if (thumb_insn_size (inst1) == 4)
- {
- *lenptr = tdep->thumb2_breakpoint_size;
- return tdep->thumb2_breakpoint;
- }
+ return ARM_BP_KIND_THUMB2;
}
}
- *lenptr = tdep->thumb_breakpoint_size;
- return tdep->thumb_breakpoint;
+ return ARM_BP_KIND_THUMB;
}
else
+ return ARM_BP_KIND_ARM;
+
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method. */
+
+static const gdb_byte *
+arm_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ switch (kind)
{
- *lenptr = tdep->arm_breakpoint_size;
+ case ARM_BP_KIND_ARM:
+ *size = tdep->arm_breakpoint_size;
return tdep->arm_breakpoint;
+ case ARM_BP_KIND_THUMB:
+ *size = tdep->thumb_breakpoint_size;
+ return tdep->thumb_breakpoint;
+ case ARM_BP_KIND_THUMB2:
+ *size = tdep->thumb2_breakpoint_size;
+ return tdep->thumb2_breakpoint;
+ default:
+ gdb_assert_not_reached ("unexpected arm breakpoint kind");
}
}
-static void
-arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
- int *kindptr)
+/* Implement the breakpoint_kind_from_current_state gdbarch method. */
+
+static int
+arm_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR *pcptr)
{
- arm_breakpoint_from_pc (gdbarch, pcptr, kindptr);
+ gdb_byte buf[4];
+
+ /* Check the memory pointed by PC is readable. */
+ if (target_read_memory (regcache_read_pc (regcache), buf, 4) == 0)
+ {
+ struct arm_get_next_pcs next_pcs_ctx;
+ CORE_ADDR pc;
+ int i;
+ VEC (CORE_ADDR) *next_pcs = NULL;
+ struct cleanup *old_chain
+ = make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs);
+
+ arm_get_next_pcs_ctor (&next_pcs_ctx,
+ &arm_get_next_pcs_ops,
+ gdbarch_byte_order (gdbarch),
+ gdbarch_byte_order_for_code (gdbarch),
+ 0,
+ regcache);
- if (arm_pc_is_thumb (gdbarch, *pcptr) && *kindptr == 4)
- /* The documented magic value for a 32-bit Thumb-2 breakpoint, so
- that this is not confused with a 32-bit ARM breakpoint. */
- *kindptr = 3;
+ next_pcs = arm_get_next_pcs (&next_pcs_ctx);
+
+ /* If MEMADDR is the next instruction of current pc, do the
+ software single step computation, and get the thumb mode by
+ the destination address. */
+ for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
+ {
+ if (UNMAKE_THUMB_ADDR (pc) == *pcptr)
+ {
+ do_cleanups (old_chain);
+
+ if (IS_THUMB_ADDR (pc))
+ {
+ *pcptr = MAKE_THUMB_ADDR (*pcptr);
+ return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
+ }
+ else
+ return ARM_BP_KIND_ARM;
+ }
+ }
+
+ do_cleanups (old_chain);
+ }
+
+ return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
}
/* Extract from an array REGBUF containing the (raw) register state a
static void
arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
{
- if (ARM_SYM_BRANCH_TYPE (&((elf_symbol_type *)sym)->internal_elf_sym)
+ elf_symbol_type *elfsym = (elf_symbol_type *) sym;
+
+ if (ARM_GET_SYM_BRANCH_TYPE (elfsym->internal_elf_sym.st_target_internal)
== ST_BRANCH_TO_THUMB)
MSYMBOL_SET_SPECIAL (msym);
}
/* Otherwise we don't have a useful guess. */
}
+/* Implement the code_of_frame_writable gdbarch method. */
+
+static int
+arm_code_of_frame_writable (struct gdbarch *gdbarch, struct frame_info *frame)
+{
+ if (gdbarch_tdep (gdbarch)->is_m
+ && get_frame_type (frame) == SIGTRAMP_FRAME)
+ {
+ /* M-profile exception frames return to some magic PCs, where
+ isn't writable at all. */
+ return 0;
+ }
+ else
+ return 1;
+}
+
\f
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
set_gdbarch_frame_align (gdbarch, arm_frame_align);
+ if (is_m)
+ set_gdbarch_code_of_frame_writable (gdbarch, arm_code_of_frame_writable);
+
set_gdbarch_write_pc (gdbarch, arm_write_pc);
/* Frame handling. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
/* Breakpoint manipulation. */
- set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
- set_gdbarch_remote_breakpoint_from_pc (gdbarch,
- arm_remote_breakpoint_from_pc);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, arm_breakpoint_kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch, arm_sw_breakpoint_from_kind);
+ set_gdbarch_breakpoint_kind_from_current_state (gdbarch,
+ arm_breakpoint_kind_from_current_state);
/* Information about registers, etc. */
set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
frame_unwind_append_unwinder (gdbarch, &arm_stub_unwind);
dwarf2_append_unwinders (gdbarch);
frame_unwind_append_unwinder (gdbarch, &arm_exidx_unwind);
+ frame_unwind_append_unwinder (gdbarch, &arm_epilogue_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arm_prologue_unwind);
/* Now we have tuned the configuration, set a few final things,
{
/* SPSR is going to be changed. */
/* We need to get SPSR value, which is yet to be done. */
- printf_unfiltered (_("Process record does not support "
- "instruction 0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch,
- arm_insn_r->this_addr));
return -1;
}
}
arm_insn_r->reg_rec_count = 2;
/* Save SPSR also;how? */
- printf_unfiltered (_("Process record does not support "
- "instruction 0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
return -1;
}
else if(8 == bits (arm_insn_r->arm_insn, 4, 7)
{
/* SPSR is going to be changed. */
/* we need to get SPSR value, which is yet to be done */
- printf_unfiltered (_("Process record does not support "
- "instruction 0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch,
- arm_insn_r->this_addr));
return -1;
}
}
/* To be done for ARMv5 and later; as of now we return -1. */
if (-1 == ret)
- printf_unfiltered (_("Process record does not support instruction x%0x "
- "at address %s.\n"),arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
-
+ return ret;
REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
{
/* SPSR is going to be changed. */
/* How to read SPSR value? */
- printf_unfiltered (_("Process record does not support instruction "
- "0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
return -1;
}
}
arm_insn_r->reg_rec_count = 2;
/* Save SPSR also; how? */
- printf_unfiltered (_("Process record does not support instruction "
- "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch,
- arm_insn_r->this_addr));
return -1;
}
else if (11 == arm_insn_r->decode
return 0;
}
+static int
+arm_record_media (insn_decode_record *arm_insn_r)
+{
+ uint32_t record_buf[8];
+
+ switch (bits (arm_insn_r->arm_insn, 22, 24))
+ {
+ case 0:
+ /* Parallel addition and subtraction, signed */
+ case 1:
+ /* Parallel addition and subtraction, unsigned */
+ case 2:
+ case 3:
+ /* Packing, unpacking, saturation and reversal */
+ {
+ int rd = bits (arm_insn_r->arm_insn, 12, 15);
+
+ record_buf[arm_insn_r->reg_rec_count++] = rd;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Signed multiplies */
+ {
+ int rd = bits (arm_insn_r->arm_insn, 16, 19);
+ unsigned int op1 = bits (arm_insn_r->arm_insn, 20, 22);
+
+ record_buf[arm_insn_r->reg_rec_count++] = rd;
+ if (op1 == 0x0)
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
+ else if (op1 == 0x4)
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 12, 15);
+ }
+ break;
+
+ case 6:
+ {
+ if (bit (arm_insn_r->arm_insn, 21)
+ && bits (arm_insn_r->arm_insn, 5, 6) == 0x2)
+ {
+ /* SBFX */
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 12, 15);
+ }
+ else if (bits (arm_insn_r->arm_insn, 20, 21) == 0x0
+ && bits (arm_insn_r->arm_insn, 5, 7) == 0x0)
+ {
+ /* USAD8 and USADA8 */
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 16, 19);
+ }
+ }
+ break;
+
+ case 7:
+ {
+ if (bits (arm_insn_r->arm_insn, 20, 21) == 0x3
+ && bits (arm_insn_r->arm_insn, 5, 7) == 0x7)
+ {
+ /* Permanently UNDEFINED */
+ return -1;
+ }
+ else
+ {
+ /* BFC, BFI and UBFX */
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 12, 15);
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
+
+ return 0;
+}
+
/* Handle ARM mode instructions with opcode 010. */
static int
LONGEST s_word;
ULONGEST u_regval[2];
+ if (bit (arm_insn_r->arm_insn, 4))
+ return arm_record_media (arm_insn_r);
+
arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
uint32_t bits_a, bit_c, bit_l, reg_t, reg_v;
uint32_t record_buf[4];
- const int num_regs = gdbarch_num_regs (arm_insn_r->gdbarch);
reg_t = bits (arm_insn_r->arm_insn, 12, 15);
reg_v = bits (arm_insn_r->arm_insn, 21, 23);
bits_a = bits (arm_insn_r->arm_insn, 21, 23);
/* Handle VMOV instruction. */
if (bits_a == 0x00)
{
- if (bit (arm_insn_r->arm_insn, 20))
- record_buf[0] = reg_t;
- else
- record_buf[0] = num_regs + (bit (arm_insn_r->arm_insn, 7) |
- (reg_v << 1));
-
+ record_buf[0] = reg_t;
arm_insn_r->reg_rec_count = 1;
}
/* Handle VMRS instruction. */
/* Handle VMOV instruction. */
if (bits_a == 0x00)
{
- if (bit (arm_insn_r->arm_insn, 20))
- record_buf[0] = reg_t;
- else
- record_buf[0] = num_regs + (bit (arm_insn_r->arm_insn, 7) |
- (reg_v << 1));
+ record_buf[0] = ARM_D0_REGNUM + reg_v;
arm_insn_r->reg_rec_count = 1;
}
ULONGEST u_regval = 0;
struct regcache *reg_cache = arm_insn_r->regcache;
- const int num_regs = gdbarch_num_regs (arm_insn_r->gdbarch);
opcode = bits (arm_insn_r->arm_insn, 20, 24);
- single_reg = bit (arm_insn_r->arm_insn, 8);
+ single_reg = !bit (arm_insn_r->arm_insn, 8);
op_vldm_vstm = opcode & 0x1b;
/* Handle VMOV instructions. */
if ((opcode & 0x1e) == 0x04)
{
- if (bit (arm_insn_r->arm_insn, 4))
+ if (bit (arm_insn_r->arm_insn, 20)) /* to_arm_registers bit 20? */
{
record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
}
else
{
- uint8_t reg_m = ((bits (arm_insn_r->arm_insn, 0, 3) << 1)
- | bit (arm_insn_r->arm_insn, 5));
+ uint8_t reg_m = bits (arm_insn_r->arm_insn, 0, 3);
+ uint8_t bit_m = bit (arm_insn_r->arm_insn, 5);
- if (!single_reg)
+ if (single_reg)
{
- record_buf[0] = num_regs + reg_m;
- record_buf[1] = num_regs + reg_m + 1;
- arm_insn_r->reg_rec_count = 2;
+ /* The first S register number m is REG_M:M (M is bit 5),
+ the corresponding D register number is REG_M:M / 2, which
+ is REG_M. */
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_D0_REGNUM + reg_m;
+ /* The second S register number is REG_M:M + 1, the
+ corresponding D register number is (REG_M:M + 1) / 2.
+ IOW, if bit M is 1, the first and second S registers
+ are mapped to different D registers, otherwise, they are
+ in the same D register. */
+ if (bit_m)
+ {
+ record_buf[arm_insn_r->reg_rec_count++]
+ = ARM_D0_REGNUM + reg_m + 1;
+ }
}
else
{
- record_buf[0] = reg_m + ARM_D0_REGNUM;
+ record_buf[0] = ((bit_m << 4) + reg_m + ARM_D0_REGNUM);
arm_insn_r->reg_rec_count = 1;
}
}
reg_rn = bits (arm_insn_r->arm_insn, 16, 19);
regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
imm_off8 = bits (arm_insn_r->arm_insn, 0, 7);
- imm_off32 = imm_off8 << 24;
+ imm_off32 = imm_off8 << 2;
memory_count = imm_off8;
if (bit (arm_insn_r->arm_insn, 23))
while (memory_count > 0)
{
- if (!single_reg)
+ if (single_reg)
{
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
start_address = start_address + 4;
memory_index = memory_index + 2;
}
else
{
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
- record_buf_mem[memory_index + 2] = start_address + 4;
- record_buf_mem[memory_index + 3] = 4;
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
+ record_buf_mem[memory_index + 2] = 4;
+ record_buf_mem[memory_index + 3] = start_address + 4;
start_address = start_address + 8;
memory_index = memory_index + 4;
}
{
uint32_t reg_count, reg_vd;
uint32_t reg_index = 0;
+ uint32_t bit_d = bit (arm_insn_r->arm_insn, 22);
reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
reg_count = bits (arm_insn_r->arm_insn, 0, 7);
- if (single_reg)
- reg_vd = reg_vd | (bit (arm_insn_r->arm_insn, 22) << 4);
- else
- reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
+ /* REG_VD is the first D register number. If the instruction
+ loads memory to S registers (SINGLE_REG is TRUE), the register
+ number is (REG_VD << 1 | bit D), so the corresponding D
+ register number is (REG_VD << 1 | bit D) / 2 = REG_VD. */
+ if (!single_reg)
+ reg_vd = reg_vd | (bit_d << 4);
- if (bit (arm_insn_r->arm_insn, 21))
+ if (bit (arm_insn_r->arm_insn, 21) /* write back */)
record_buf[reg_index++] = bits (arm_insn_r->arm_insn, 16, 19);
- while (reg_count > 0)
+ /* If the instruction loads memory to D register, REG_COUNT should
+ be divided by 2, according to the ARM Architecture Reference
+ Manual. If the instruction loads memory to S register, divide by
+ 2 as well because two S registers are mapped to D register. */
+ reg_count = reg_count / 2;
+ if (single_reg && bit_d)
{
- if (single_reg)
- record_buf[reg_index++] = num_regs + reg_vd + reg_count - 1;
- else
- record_buf[reg_index++] = ARM_D0_REGNUM + reg_vd + reg_count - 1;
+ /* Increase the register count if S register list starts from
+ an odd number (bit d is one). */
+ reg_count++;
+ }
+ while (reg_count > 0)
+ {
+ record_buf[reg_index++] = ARM_D0_REGNUM + reg_vd + reg_count - 1;
reg_count--;
}
arm_insn_r->reg_rec_count = reg_index;
reg_rn = bits (arm_insn_r->arm_insn, 16, 19);
regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
imm_off8 = bits (arm_insn_r->arm_insn, 0, 7);
- imm_off32 = imm_off8 << 24;
+ imm_off32 = imm_off8 << 2;
if (bit (arm_insn_r->arm_insn, 23))
start_address = u_regval + imm_off32;
if (single_reg)
{
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
arm_insn_r->mem_rec_count = 1;
}
else
{
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
- record_buf_mem[memory_index + 2] = start_address + 4;
- record_buf_mem[memory_index + 3] = 4;
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
+ record_buf_mem[memory_index + 2] = 4;
+ record_buf_mem[memory_index + 3] = start_address + 4;
arm_insn_r->mem_rec_count = 2;
}
}
else
{
reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
- record_buf[0] = num_regs + reg_vd;
+ /* Record register D rather than pseudo register S. */
+ record_buf[0] = ARM_D0_REGNUM + reg_vd / 2;
}
arm_insn_r->reg_rec_count = 1;
}
}
else
{
- /* Format 8; special data processing insns. */
- reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = reg_src1;
+ /* Format 8; special data processing insns. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = (bit (thumb_insn_r->arm_insn, 7) << 3
+ | bits (thumb_insn_r->arm_insn, 0, 2));
thumb_insn_r->reg_rec_count = 2;
}
}
{
arm_record->cond = bits (arm_record->arm_insn, 28, 31);
insn_id = bits (arm_record->arm_insn, 25, 27);
- ret = arm_record_extension_space (arm_record);
- /* If this insn has fallen into extension space
- then we need not decode it anymore. */
- if (ret != -1 && !INSN_RECORDED(arm_record))
+
+ if (arm_record->cond == 0xf)
+ ret = arm_record_extension_space (arm_record);
+ else
{
+ /* If this insn has fallen into extension space
+ then we need not decode it anymore. */
ret = arm_handle_insn[insn_id] (arm_record);
}
+ if (ret != ARM_RECORD_SUCCESS)
+ {
+ arm_record_unsupported_insn (arm_record);
+ ret = -1;
+ }
}
else if (THUMB_RECORD == record_type)
{
arm_record->cond = -1;
insn_id = bits (arm_record->arm_insn, 13, 15);
ret = thumb_handle_insn[insn_id] (arm_record);
+ if (ret != ARM_RECORD_SUCCESS)
+ {
+ arm_record_unsupported_insn (arm_record);
+ ret = -1;
+ }
}
else if (THUMB2_RECORD == record_type)
{
arm_record->arm_insn
= (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);
- insn_id = thumb2_record_decode_insn_handler (arm_record);
+ ret = thumb2_record_decode_insn_handler (arm_record);
- if (insn_id != ARM_RECORD_SUCCESS)
+ if (ret != ARM_RECORD_SUCCESS)
{
arm_record_unsupported_insn (arm_record);
ret = -1;