/* Common target dependent code for GDB on ARM systems.
- Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "defs.h"
+
#include <ctype.h> /* XXX for isupper (). */
-#include "defs.h"
#include "frame.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbcmd.h"
#include "gdbcore.h"
-#include "gdb_string.h"
#include "dis-asm.h" /* For register styles. */
#include "regcache.h"
#include "reggroups.h"
#include "dwarf2-frame.h"
#include "gdbtypes.h"
#include "prologue-value.h"
+#include "remote.h"
#include "target-descriptions.h"
#include "user-regs.h"
#include "observer.h"
+#include "arch/arm.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"
#include "coff/internal.h"
#include "elf/arm.h"
-#include "gdb_assert.h"
#include "vec.h"
+#include "record.h"
+#include "record-full.h"
+
#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"
/* The type of floating-point to use. Keep this in sync with enum
arm_float_model, and the help string in _initialize_arm_tdep. */
-static const char *fp_model_strings[] =
+static const char *const fp_model_strings[] =
{
"auto",
"softfpa",
static const char *current_fp_model = "auto";
/* The ABI to use. Keep this in sync with arm_abi_kind. */
-static const char *arm_abi_strings[] =
+static const char *const arm_abi_strings[] =
{
"auto",
"APCS",
static const char *arm_abi_string = "auto";
/* The execution mode to assume. */
-static const char *arm_mode_strings[] =
+static const char *const arm_mode_strings[] =
{
"auto",
"arm",
struct regcache *regcache,
int regnum, const gdb_byte *buf);
-static int thumb_insn_size (unsigned short inst1);
-
struct arm_prologue_cache
{
/* The stack pointer at the time this frame was created; i.e. the
#define DISPLACED_STEPPING_ARCH_VERSION 5
-/* Addresses for calling Thumb functions have the bit 0 set.
- Here are some macros to test, set, or clear bit 0 of addresses. */
-#define IS_THUMB_ADDR(addr) ((addr) & 1)
-#define MAKE_THUMB_ADDR(addr) ((addr) | 1)
-#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
-
/* Set to true if the 32-bit mode is in use. */
int arm_apcs_32 = 1;
0 };
unsigned int idx;
- data = objfile_data (sec->objfile, arm_objfile_data_key);
+ data = (struct arm_per_objfile *) objfile_data (sec->objfile,
+ arm_objfile_data_key);
if (data != NULL)
{
map = data->section_maps[sec->the_bfd_section->index];
int
arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
{
- struct obj_section *sec;
- struct minimal_symbol *sym;
+ struct bound_minimal_symbol sym;
char type;
struct displaced_step_closure* dsc
= get_displaced_step_closure_by_addr(memaddr);
/* Thumb functions have a "special" bit set in minimal symbols. */
sym = lookup_minimal_symbol_by_pc (memaddr);
- if (sym)
- return (MSYMBOL_IS_SPECIAL (sym));
+ if (sym.minsym)
+ return (MSYMBOL_IS_SPECIAL (sym.minsym));
/* If the user wants to override the fallback mode, let them. */
if (strcmp (arm_fallback_mode_string, "arm") == 0)
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)
+ return val;
+
if (arm_apcs_32)
return UNMAKE_THUMB_ADDR (val);
else
return (val & 0x03fffffc);
}
-/* When reading symbols, we need to zap the low bit of the address,
- which may be set to 1 for Thumb functions. */
-static CORE_ADDR
-arm_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR val)
-{
- return val & ~1;
-}
-
/* Return 1 if PC is the start of a compiler helper function which
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
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;
+ struct bound_minimal_symbol msym;
msym = lookup_minimal_symbol_by_pc (pc);
- if (msym != NULL
- && SYMBOL_VALUE_ADDRESS (msym) == pc
- && SYMBOL_LINKAGE_NAME (msym) != NULL)
+ if (msym.minsym != NULL
+ && BMSYMBOL_VALUE_ADDRESS (msym) == pc
+ && MSYMBOL_LINKAGE_NAME (msym.minsym) != NULL)
{
- const char *name = SYMBOL_LINKAGE_NAME (msym);
+ const char *name = MSYMBOL_LINKAGE_NAME (msym.minsym);
/* The GNU linker's Thumb call stub to foo is named
__foo_from_thumb. */
/* 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)
+ if (startswith (name, "__truncdfsf2"))
return 1;
- if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+ if (startswith (name, "__aeabi_d2f"))
return 1;
/* Internal functions related to thread-local storage. */
- if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
+ if (startswith (name, "__tls_get_addr"))
return 1;
- if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
+ if (startswith (name, "__aeabi_read_tp"))
return 1;
}
else
#define sbits(obj,st,fn) \
((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
#define BranchDest(addr,instr) \
- ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
+ ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
/* Extract the immediate from instruction movw/movt of encoding T. INSN1 is
the first 16-bit of instruction, and INSN2 is the second 16-bit of
return 0;
}
+/* Return 1 if the 16-bit Thumb instruction INSN restores SP in
+ epilogue, 0 otherwise. */
+
+static int
+thumb_instruction_restores_sp (unsigned short insn)
+{
+ return (insn == 0x46bd /* mov sp, r7 */
+ || (insn & 0xff80) == 0xb000 /* add sp, imm */
+ || (insn & 0xfe00) == 0xbc00); /* pop <registers> */
+}
+
/* Analyze a Thumb prologue, looking for a recognizable stack frame
and frame pointer. Scan until we encounter a store that could
clobber the stack frame unexpectedly, or an unknown instruction.
pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
}
}
- else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
- sub sp, #simm */
+ else if ((insn & 0xff80) == 0xb080) /* sub sp, #imm */
{
offset = (insn & 0x7f) << 2; /* get scaled offset */
- if (insn & 0x80) /* Check for SUB. */
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- -offset);
- else
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- offset);
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+ -offset);
+ }
+ else if (thumb_instruction_restores_sp (insn))
+ {
+ /* Don't scan past the epilogue. */
+ break;
}
else if ((insn & 0xf800) == 0xa800) /* add Rd, sp, #imm */
regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
unsigned int constant;
CORE_ADDR loc;
- offset = bits (insn, 0, 11);
+ offset = bits (inst2, 0, 11);
if (insn & 0x0080)
loc = start + 4 + offset;
else
unsigned int constant;
CORE_ADDR loc;
- offset = bits (insn, 0, 7) << 2;
+ offset = bits (inst2, 0, 7) << 2;
if (insn & 0x0080)
loc = start + 4 + offset;
else
cache->framereg = THUMB_FP_REGNUM;
cache->framesize = -regs[THUMB_FP_REGNUM].k;
}
- else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
+ else
{
/* Try the stack pointer... this is a bit desperate. */
cache->framereg = ARM_SP_REGNUM;
cache->framesize = -regs[ARM_SP_REGNUM].k;
}
- else
- {
- /* We're just out of luck. We don't know where the frame is. */
- cache->framereg = -1;
- cache->framesize = 0;
- }
for (i = 0; i < 16; i++)
if (pv_area_find_reg (stack, gdbarch, i, &offset))
{
*destreg = bits (insn1, 8, 10);
*offset = 2;
- address = bits (insn1, 0, 7);
+ address = (pc & 0xfffffffc) + 4 + (bits (insn1, 0, 7) << 2);
+ address = read_memory_unsigned_integer (address, 4,
+ byte_order_for_code);
}
else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */
{
unsigned int insn
= read_memory_unsigned_integer (pc, 4, byte_order_for_code);
- if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, #immed */
+ if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, [PC, #immed] */
{
- address = bits (insn, 0, 11);
+ address = bits (insn, 0, 11) + pc + 8;
+ address = read_memory_unsigned_integer (address, 4,
+ byte_order_for_code);
+
*destreg = bits (insn, 12, 15);
*offset = 4;
}
arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- unsigned int address, basereg;
- struct minimal_symbol *stack_chk_guard;
+ unsigned int basereg;
+ struct bound_minimal_symbol stack_chk_guard;
int offset;
int is_thumb = arm_pc_is_thumb (gdbarch, pc);
CORE_ADDR addr;
return pc;
stack_chk_guard = lookup_minimal_symbol_by_pc (addr);
- /* If name of symbol doesn't start with '__stack_chk_guard', this
- instruction sequence is not for stack protector. If symbol is
- removed, we conservatively think this sequence is for stack protector. */
- if (stack_chk_guard
- && strncmp (SYMBOL_LINKAGE_NAME (stack_chk_guard), "__stack_chk_guard",
- strlen ("__stack_chk_guard")) != 0)
+ /* ADDR must correspond to a symbol whose name is __stack_chk_guard.
+ Otherwise, this sequence cannot be for stack protector. */
+ if (stack_chk_guard.minsym == NULL
+ || !startswith (MSYMBOL_LINKAGE_NAME (stack_chk_guard.minsym), "__stack_chk_guard"))
return pc;
if (is_thumb)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned long inst;
- CORE_ADDR skip_pc;
CORE_ADDR func_addr, limit_pc;
- struct symtab_and_line sal;
/* See if we can determine the end of the prologue via the symbol table.
If so, then return either PC, or the PC after the prologue, whichever
{
CORE_ADDR post_prologue_pc
= skip_prologue_using_sal (gdbarch, func_addr);
- struct symtab *s = find_pc_symtab (func_addr);
+ struct compunit_symtab *cust = find_pc_compunit_symtab (func_addr);
if (post_prologue_pc)
post_prologue_pc
will have producer information for most binaries; if it is
missing (e.g. for -gstabs), assuming the GNU tools. */
if (post_prologue_pc
- && (s == NULL
- || s->producer == NULL
- || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0))
+ && (cust == NULL
+ || COMPUNIT_PRODUCER (cust) == NULL
+ || startswith (COMPUNIT_PRODUCER (cust), "GNU ")
+ || startswith (COMPUNIT_PRODUCER (cust), "clang ")))
return post_prologue_pc;
if (post_prologue_pc != 0)
/* Check if this is Thumb code. */
if (arm_pc_is_thumb (gdbarch, pc))
return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL);
-
- for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4)
- {
- inst = read_memory_unsigned_integer (skip_pc, 4, byte_order_for_code);
-
- /* "mov ip, sp" is no longer a required part of the prologue. */
- if (inst == 0xe1a0c00d) /* mov ip, sp */
- continue;
-
- if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
- continue;
-
- /* Some prologues begin with "str lr, [sp, #-4]!". */
- if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
- continue;
-
- if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
- continue;
-
- if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
- continue;
-
- /* Any insns after this point may float into the code, if it makes
- for better instruction scheduling, so we skip them only if we
- find them, but still consider the function to be frame-ful. */
-
- /* We may have either one sfmfd instruction here, or several stfe
- insns, depending on the version of floating point code we
- support. */
- if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */
- continue;
-
- if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
- continue;
-
- if ((inst & 0xffffc000) == 0xe54b0000 /* strb r(0123),[r11,#-nn] */
- || (inst & 0xffffc0f0) == 0xe14b00b0 /* strh r(0123),[r11,#-nn] */
- || (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */
- continue;
-
- if ((inst & 0xffffc000) == 0xe5cd0000 /* strb r(0123),[sp,#nn] */
- || (inst & 0xffffc0f0) == 0xe1cd00b0 /* strh r(0123),[sp,#nn] */
- || (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */
- continue;
-
- /* Un-recognized instruction; stop scanning. */
- break;
- }
-
- return skip_pc; /* End of prologue. */
+ else
+ return arm_analyze_prologue (gdbarch, pc, limit_pc, NULL);
}
/* *INDENT-OFF* */
{
CORE_ADDR prologue_start;
CORE_ADDR prologue_end;
- CORE_ADDR current_pc;
if (find_pc_partial_function (block_addr, NULL, &prologue_start,
&prologue_end))
}
}
+/* Return 1 if the ARM instruction INSN restores SP in epilogue, 0
+ otherwise. */
+
+static int
+arm_instruction_restores_sp (unsigned int insn)
+{
+ if (bits (insn, 28, 31) != INST_NV)
+ {
+ if ((insn & 0x0df0f000) == 0x0080d000
+ /* ADD SP (register or immediate). */
+ || (insn & 0x0df0f000) == 0x0040d000
+ /* SUB SP (register or immediate). */
+ || (insn & 0x0ffffff0) == 0x01a0d000
+ /* MOV SP. */
+ || (insn & 0x0fff0000) == 0x08bd0000
+ /* POP (LDMIA). */
+ || (insn & 0x0fff0000) == 0x049d0000)
+ /* POP of a single register. */
+ return 1;
+ }
+
+ return 0;
+}
+
/* Analyze an ARM mode prologue starting at PROLOGUE_START and
continuing no further than PROLOGUE_END. If CACHE is non-NULL,
fill it in. Return the first address not recognized as a prologue
pv_t regs[ARM_FPS_REGNUM];
struct pv_area *stack;
struct cleanup *back_to;
- int framereg, framesize;
CORE_ADDR unrecognized_pc = 0;
/* Search the prologue looking for instructions that set up the
else if (arm_instruction_changes_pc (insn))
/* Don't scan past anything that might change control flow. */
break;
+ else if (arm_instruction_restores_sp (insn))
+ {
+ /* Don't scan past the epilogue. */
+ 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
continue;
else
{
- /* The optimizer might shove anything into the prologue,
- so we just skip what we don't recognize. */
+ /* The optimizer might shove anything into the prologue, if
+ we build up cache (cache != NULL) from scanning prologue,
+ we just skip what we don't recognize and scan further to
+ make cache as complete as possible. However, if we skip
+ prologue, we'll stop immediately on unrecognized
+ instruction. */
unrecognized_pc = current_pc;
- continue;
+ if (cache != NULL)
+ continue;
+ else
+ break;
}
}
if (unrecognized_pc == 0)
unrecognized_pc = current_pc;
- /* The frame size is just the distance from the frame register
- to the original stack pointer. */
- if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
- {
- /* Frame pointer is fp. */
- framereg = ARM_FP_REGNUM;
- framesize = -regs[ARM_FP_REGNUM].k;
- }
- else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
- {
- /* Try the stack pointer... this is a bit desperate. */
- framereg = ARM_SP_REGNUM;
- framesize = -regs[ARM_SP_REGNUM].k;
- }
- else
- {
- /* We're just out of luck. We don't know where the frame is. */
- framereg = -1;
- framesize = 0;
- }
-
if (cache)
{
+ int framereg, framesize;
+
+ /* The frame size is just the distance from the frame register
+ to the original stack pointer. */
+ if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
+ {
+ /* Frame pointer is fp. */
+ framereg = ARM_FP_REGNUM;
+ framesize = -regs[ARM_FP_REGNUM].k;
+ }
+ else
+ {
+ /* Try the stack pointer... this is a bit desperate. */
+ framereg = ARM_SP_REGNUM;
+ framesize = -regs[ARM_SP_REGNUM].k;
+ }
+
cache->framereg = framereg;
cache->framesize = framesize;
return cache;
}
+/* Implementation of the stop_reason hook for arm_prologue frames. */
+
+static enum unwind_stop_reason
+arm_prologue_unwind_stop_reason (struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct arm_prologue_cache *cache;
+ CORE_ADDR pc;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (this_frame);
+ cache = (struct arm_prologue_cache *) *this_cache;
+
+ /* This is meant to halt the backtrace at "_start". */
+ pc = get_frame_pc (this_frame);
+ if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
+ return UNWIND_OUTERMOST;
+
+ /* If we've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return UNWIND_OUTERMOST;
+
+ return UNWIND_NO_REASON;
+}
+
/* Our frame ID for a normal frame is the current function's starting PC
and the caller's SP when we were called. */
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache (this_frame);
- cache = *this_cache;
-
- /* This is meant to halt the backtrace at "_start". */
- pc = get_frame_pc (this_frame);
- if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
- return;
-
- /* If we've hit a wall, stop. */
- if (cache->prev_sp == 0)
- return;
+ 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)
func = pc;
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache (this_frame);
- cache = *this_cache;
+ cache = (struct arm_prologue_cache *) *this_cache;
/* If we are asked to unwind the PC, then we need to return the LR
instead. The prologue may save PC, but it will point into this
struct frame_unwind arm_prologue_unwind = {
NORMAL_FRAME,
- default_frame_unwind_stop_reason,
+ arm_prologue_unwind_stop_reason,
arm_prologue_this_id,
arm_prologue_prev_register,
NULL,
static void
arm_exidx_data_free (struct objfile *objfile, void *arg)
{
- struct arm_exidx_data *data = arg;
+ struct arm_exidx_data *data = (struct arm_exidx_data *) arg;
unsigned int i;
for (i = 0; i < objfile->obfd->section_count; i++)
{
exidx_vma = bfd_section_vma (objfile->obfd, exidx);
exidx_size = bfd_get_section_size (exidx);
- exidx_data = xmalloc (exidx_size);
+ exidx_data = (gdb_byte *) xmalloc (exidx_size);
make_cleanup (xfree, exidx_data);
if (!bfd_get_section_contents (objfile->obfd, exidx,
{
extab_vma = bfd_section_vma (objfile->obfd, extab);
extab_size = bfd_get_section_size (extab);
- extab_data = xmalloc (extab_size);
+ extab_data = (gdb_byte *) xmalloc (extab_size);
make_cleanup (xfree, extab_data);
if (!bfd_get_section_contents (objfile->obfd, extab,
extab section starting at ADDR. */
if (n_bytes || n_words)
{
- gdb_byte *p = entry = obstack_alloc (&objfile->objfile_obstack,
- n_bytes + n_words * 4 + 1);
+ gdb_byte *p = entry
+ = (gdb_byte *) obstack_alloc (&objfile->objfile_obstack,
+ n_bytes + n_words * 4 + 1);
while (n_bytes--)
*p++ = (gdb_byte) ((word >> (8 * n_bytes)) & 0xff);
struct arm_exidx_entry map_key = { memaddr - obj_section_addr (sec), 0 };
unsigned int idx;
- data = objfile_data (sec->objfile, arm_exidx_data_key);
+ data = ((struct arm_exidx_data *)
+ objfile_data (sec->objfile, arm_exidx_data_key));
if (data != NULL)
{
map = data->section_maps[sec->the_bfd_section->index];
arm_exidx_unwind_sniffer
};
+/* Recognize GCC's trampoline for thumb call-indirect. If we are in a
+ trampoline, return the target PC. Otherwise return 0.
+
+ void call0a (char c, short s, int i, long l) {}
+
+ int main (void)
+ {
+ (*pointer_to_call0a) (c, s, i, l);
+ }
+
+ Instead of calling a stub library function _call_via_xx (xx is
+ the register name), GCC may inline the trampoline in the object
+ file as below (register r2 has the address of call0a).
+
+ .global main
+ .type main, %function
+ ...
+ bl .L1
+ ...
+ .size main, .-main
+
+ .L1:
+ bx r2
+
+ The trampoline 'bx r2' doesn't belong to main. */
+
+static CORE_ADDR
+arm_skip_bx_reg (struct frame_info *frame, CORE_ADDR pc)
+{
+ /* The heuristics of recognizing such trampoline is that FRAME is
+ executing in Thumb mode and the instruction on PC is 'bx Rm'. */
+ if (arm_frame_is_thumb (frame))
+ {
+ gdb_byte buf[2];
+
+ if (target_read_memory (pc, buf, 2) == 0)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order_for_code
+ = gdbarch_byte_order_for_code (gdbarch);
+ uint16_t insn
+ = extract_unsigned_integer (buf, 2, byte_order_for_code);
+
+ if ((insn & 0xff80) == 0x4700) /* bx <Rm> */
+ {
+ CORE_ADDR dest
+ = get_frame_register_unsigned (frame, bits (insn, 3, 6));
+
+ /* Clear the LSB so that gdb core sets step-resume
+ breakpoint at the right address. */
+ return UNMAKE_THUMB_ADDR (dest);
+ }
+ }
+ }
+
+ return 0;
+}
+
static struct arm_prologue_cache *
arm_make_stub_cache (struct frame_info *this_frame)
{
if (*this_cache == NULL)
*this_cache = arm_make_stub_cache (this_frame);
- cache = *this_cache;
+ cache = (struct arm_prologue_cache *) *this_cache;
*this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
}
void **this_prologue_cache)
{
CORE_ADDR addr_in_block;
- char dummy[4];
+ gdb_byte dummy[4];
+ CORE_ADDR pc, start_addr;
+ const char *name;
addr_in_block = get_frame_address_in_block (this_frame);
- if (in_plt_section (addr_in_block, NULL)
+ pc = get_frame_pc (this_frame);
+ if (in_plt_section (addr_in_block)
/* We also use the stub winder if the target memory is unreadable
to avoid having the prologue unwinder trying to read it. */
- || target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0)
+ || target_read_memory (pc, dummy, 4) != 0)
+ return 1;
+
+ if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0
+ && arm_skip_bx_reg (this_frame, pc) != 0)
return 1;
return 0;
arm_stub_unwind_sniffer
};
+/* Put here the code to store, into CACHE->saved_regs, the addresses
+ of the saved registers of frame described by THIS_FRAME. CACHE is
+ returned. */
+
+static struct arm_prologue_cache *
+arm_m_exception_cache (struct frame_info *this_frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_sp;
+ LONGEST xpsr;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ unwound_sp = get_frame_register_unsigned (this_frame,
+ ARM_SP_REGNUM);
+
+ /* The hardware saves eight 32-bit words, comprising xPSR,
+ ReturnAddress, LR (R14), R12, R3, R2, R1, R0. See details in
+ "B1.5.6 Exception entry behavior" in
+ "ARMv7-M Architecture Reference Manual". */
+ cache->saved_regs[0].addr = unwound_sp;
+ cache->saved_regs[1].addr = unwound_sp + 4;
+ cache->saved_regs[2].addr = unwound_sp + 8;
+ cache->saved_regs[3].addr = unwound_sp + 12;
+ cache->saved_regs[12].addr = unwound_sp + 16;
+ cache->saved_regs[14].addr = unwound_sp + 20;
+ cache->saved_regs[15].addr = unwound_sp + 24;
+ cache->saved_regs[ARM_PS_REGNUM].addr = unwound_sp + 28;
+
+ /* If bit 9 of the saved xPSR is set, then there is a four-byte
+ aligner between the top of the 32-byte stack frame and the
+ previous context's stack pointer. */
+ cache->prev_sp = unwound_sp + 32;
+ if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr)
+ && (xpsr & (1 << 9)) != 0)
+ cache->prev_sp += 4;
+
+ return cache;
+}
+
+/* Implementation of function hook 'this_id' in
+ 'struct frame_uwnind'. */
+
+static void
+arm_m_exception_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_m_exception_cache (this_frame);
+ cache = (struct arm_prologue_cache *) *this_cache;
+
+ /* Our frame ID for a stub frame is the current SP and LR. */
+ *this_id = frame_id_build (cache->prev_sp,
+ get_frame_pc (this_frame));
+}
+
+/* Implementation of function hook 'prev_register' in
+ 'struct frame_uwnind'. */
+
+static struct value *
+arm_m_exception_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int prev_regnum)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_m_exception_cache (this_frame);
+ cache = (struct arm_prologue_cache *) *this_cache;
+
+ /* The value was already reconstructed into PREV_SP. */
+ if (prev_regnum == ARM_SP_REGNUM)
+ return frame_unwind_got_constant (this_frame, prev_regnum,
+ cache->prev_sp);
+
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+ prev_regnum);
+}
+
+/* Implementation of function hook 'sniffer' in
+ 'struct frame_uwnind'. */
+
+static int
+arm_m_exception_unwind_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ CORE_ADDR this_pc = get_frame_pc (this_frame);
+
+ /* 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;
+}
+
+/* Frame unwinder for M-profile exceptions. */
+
+struct frame_unwind arm_m_exception_unwind =
+{
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arm_m_exception_this_id,
+ arm_m_exception_prev_register,
+ NULL,
+ arm_m_exception_unwind_sniffer
+};
+
static CORE_ADDR
arm_normal_frame_base (struct frame_info *this_frame, void **this_cache)
{
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache (this_frame);
- cache = *this_cache;
+ cache = (struct arm_prologue_cache *) *this_cache;
return cache->prev_sp - cache->framesize;
}
}
}
-/* Return true if we are in the function's epilogue, i.e. after the
- instruction that destroyed the function's stack frame. */
+/* Implement the stack_frame_destroyed_p gdbarch method. */
static int
-thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned int insn, insn2;
found_return = 1;
else if (insn == 0x46f7) /* mov pc, lr */
found_return = 1;
- else if (insn == 0x46bd) /* mov sp, r7 */
- found_stack_adjust = 1;
- else if ((insn & 0xff00) == 0xb000) /* add sp, imm or sub sp, imm */
- found_stack_adjust = 1;
- else if ((insn & 0xfe00) == 0xbc00) /* pop <registers> */
- {
- found_stack_adjust = 1;
- if (insn & 0x0100) /* <registers> include PC. */
+ else if (thumb_instruction_restores_sp (insn))
+ {
+ if ((insn & 0xff00) == 0xbd00) /* pop <registers, PC> */
found_return = 1;
}
else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instruction */
if (insn == 0xe8bd) /* ldm.w sp!, <registers> */
{
- found_stack_adjust = 1;
if (insn2 & 0x8000) /* <registers> include PC. */
found_return = 1;
}
else if (insn == 0xf85d /* ldr.w <Rt>, [sp], #4 */
&& (insn2 & 0x0fff) == 0x0b04)
{
- found_stack_adjust = 1;
if ((insn2 & 0xf000) == 0xf000) /* <Rt> is PC. */
found_return = 1;
}
else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, <list> */
&& (insn2 & 0x0e00) == 0x0a00)
- found_stack_adjust = 1;
+ ;
else
break;
}
a 32-bit instruction. This is just a heuristic, so we do not worry
too much about false positives. */
- if (!found_stack_adjust)
- {
- if (pc - 4 < func_start)
- return 0;
- if (target_read_memory (pc - 4, buf, 4))
- return 0;
+ if (pc - 4 < func_start)
+ return 0;
+ if (target_read_memory (pc - 4, buf, 4))
+ return 0;
- insn = extract_unsigned_integer (buf, 2, byte_order_for_code);
- insn2 = extract_unsigned_integer (buf + 2, 2, byte_order_for_code);
-
- if (insn2 == 0x46bd) /* mov sp, r7 */
- found_stack_adjust = 1;
- else if ((insn2 & 0xff00) == 0xb000) /* add sp, imm or sub sp, imm */
- found_stack_adjust = 1;
- else if ((insn2 & 0xff00) == 0xbc00) /* pop <registers> without PC */
- found_stack_adjust = 1;
- else if (insn == 0xe8bd) /* ldm.w sp!, <registers> */
- found_stack_adjust = 1;
- else if (insn == 0xf85d /* ldr.w <Rt>, [sp], #4 */
- && (insn2 & 0x0fff) == 0x0b04)
- found_stack_adjust = 1;
- else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, <list> */
- && (insn2 & 0x0e00) == 0x0a00)
- found_stack_adjust = 1;
- }
+ insn = extract_unsigned_integer (buf, 2, byte_order_for_code);
+ insn2 = extract_unsigned_integer (buf + 2, 2, byte_order_for_code);
+
+ if (thumb_instruction_restores_sp (insn2))
+ found_stack_adjust = 1;
+ else if (insn == 0xe8bd) /* ldm.w sp!, <registers> */
+ found_stack_adjust = 1;
+ else if (insn == 0xf85d /* ldr.w <Rt>, [sp], #4 */
+ && (insn2 & 0x0fff) == 0x0b04)
+ found_stack_adjust = 1;
+ else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, <list> */
+ && (insn2 & 0x0e00) == 0x0a00)
+ found_stack_adjust = 1;
return found_stack_adjust;
}
-/* Return true if we are in the function's epilogue, i.e. after the
- instruction that destroyed the function's stack frame. */
+/* Implement the stack_frame_destroyed_p gdbarch method. */
static int
-arm_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+arm_stack_frame_destroyed_p (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, found_stack_adjust;
+ int found_return;
CORE_ADDR func_start, func_end;
if (arm_pc_is_thumb (gdbarch, pc))
- return thumb_in_function_epilogue_p (gdbarch, pc);
+ return thumb_stack_frame_destroyed_p (gdbarch, pc);
if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
return 0;
if (pc < func_start + 4)
return 0;
- found_stack_adjust = 0;
insn = read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code);
- if (bits (insn, 28, 31) != INST_NV)
- {
- if ((insn & 0x0df0f000) == 0x0080d000)
- /* ADD SP (register or immediate). */
- found_stack_adjust = 1;
- else if ((insn & 0x0df0f000) == 0x0040d000)
- /* SUB SP (register or immediate). */
- found_stack_adjust = 1;
- else if ((insn & 0x0ffffff0) == 0x01a0d000)
- /* MOV SP. */
- found_stack_adjust = 1;
- else if ((insn & 0x0fff0000) == 0x08bd0000)
- /* POP (LDMIA). */
- found_stack_adjust = 1;
- }
-
- if (found_stack_adjust)
+ if (arm_instruction_restores_sp (insn))
return 1;
return 0;
{
int len;
struct stack_item *prev;
- void *data;
+ gdb_byte *data;
};
static struct stack_item *
push_stack_item (struct stack_item *prev, const void *contents, int len)
{
struct stack_item *si;
- si = xmalloc (sizeof (struct stack_item));
- si->data = xmalloc (len);
+ si = XNEW (struct stack_item);
+ si->data = (gdb_byte *) xmalloc (len);
si->len = len;
si->prev = prev;
memcpy (si->data, contents, len);
case TYPE_CODE_FLT:
case TYPE_CODE_SET:
case TYPE_CODE_RANGE:
- case TYPE_CODE_BITSTRING:
case TYPE_CODE_REF:
case TYPE_CODE_CHAR:
case TYPE_CODE_BOOL:
classified from *BASE_TYPE, or two types differently classified
from each other, return -1, otherwise return the total number of
base-type elements found (possibly 0 in an empty structure or
- array). Vectors and complex types are not currently supported,
- matching the generic AAPCS support. */
+ array). Vector types are not currently supported, matching the
+ generic AAPCS support. */
static int
arm_vfp_cprc_sub_candidate (struct type *t,
}
break;
+ case TYPE_CODE_COMPLEX:
+ /* Arguments of complex T where T is one of the types float or
+ double get treated as if they are implemented as:
+
+ struct complexT
+ {
+ T real;
+ T imag;
+ };
+
+ */
+ switch (TYPE_LENGTH (t))
+ {
+ case 8:
+ if (*base_type == VFP_CPRC_UNKNOWN)
+ *base_type = VFP_CPRC_SINGLE;
+ else if (*base_type != VFP_CPRC_SINGLE)
+ return -1;
+ return 2;
+
+ case 16:
+ if (*base_type == VFP_CPRC_UNKNOWN)
+ *base_type = VFP_CPRC_DOUBLE;
+ else if (*base_type != VFP_CPRC_DOUBLE)
+ return -1;
+ return 2;
+
+ default:
+ return -1;
+ }
+ break;
+
case TYPE_CODE_ARRAY:
{
int count;
val + i * unit_length);
else
{
- sprintf (name_buf, "%c%d", reg_char, reg_scaled + i);
+ xsnprintf (name_buf, sizeof (name_buf), "%c%d",
+ reg_char, reg_scaled + i);
regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
regcache_cooked_write (regcache, regnum,
CORE_ADDR regval = extract_unsigned_integer (val, len, byte_order);
if (arm_pc_is_thumb (gdbarch, regval))
{
- bfd_byte *copy = alloca (len);
+ bfd_byte *copy = (bfd_byte *) alloca (len);
store_unsigned_integer (copy, len, byte_order,
MAKE_THUMB_ADDR (regval));
val = copy;
}
static void
-print_fpu_flags (int flags)
+print_fpu_flags (struct ui_file *file, int flags)
{
if (flags & (1 << 0))
- fputs ("IVO ", stdout);
+ fputs_filtered ("IVO ", file);
if (flags & (1 << 1))
- fputs ("DVZ ", stdout);
+ fputs_filtered ("DVZ ", file);
if (flags & (1 << 2))
- fputs ("OFL ", stdout);
+ fputs_filtered ("OFL ", file);
if (flags & (1 << 3))
- fputs ("UFL ", stdout);
+ fputs_filtered ("UFL ", file);
if (flags & (1 << 4))
- fputs ("INX ", stdout);
- putchar ('\n');
+ fputs_filtered ("INX ", file);
+ fputc_filtered ('\n', file);
}
/* Print interesting information about the floating point processor
type = (status >> 24) & 127;
if (status & (1 << 31))
- printf (_("Hardware FPU type %d\n"), type);
+ fprintf_filtered (file, _("Hardware FPU type %d\n"), type);
else
- printf (_("Software FPU type %d\n"), type);
+ fprintf_filtered (file, _("Software FPU type %d\n"), type);
/* i18n: [floating point unit] mask */
- fputs (_("mask: "), stdout);
- print_fpu_flags (status >> 16);
+ fputs_filtered (_("mask: "), file);
+ print_fpu_flags (file, status >> 16);
/* i18n: [floating point unit] flags */
- fputs (_("flags: "), stdout);
- print_fpu_flags (status);
+ fputs_filtered (_("flags: "), file);
+ print_fpu_flags (file, status);
}
/* Construct the ARM extended floating point type. */
{
char name_buf[4];
- sprintf (name_buf, "s%d", reg - 64);
+ xsnprintf (name_buf, sizeof (name_buf), "s%d", reg - 64);
return user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
}
{
char name_buf[4];
- sprintf (name_buf, "d%d", reg - 256);
+ xsnprintf (name_buf, sizeof (name_buf), "d%d", reg - 256);
return user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
}
return nbits;
}
-/* Return the size in bytes of the complete Thumb instruction whose
- first halfword is INST1. */
-
-static int
-thumb_insn_size (unsigned short inst1)
-{
- if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
- return 4;
- else
- return 2;
-}
-
static int
thumb_advance_itstate (unsigned int itstate)
{
else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */
{
if (bits (inst1, 3, 6) == 0x0f)
- nextpc = pc_val;
+ nextpc = UNMAKE_THUMB_ADDR (pc_val);
else
nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
}
case 0x5: /* data transfer */
case 0x6:
case 0x7:
+ if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1)
+ {
+ /* Media instructions and architecturally undefined
+ instructions. */
+ break;
+ }
+
if (bit (this_instr, 20))
{
/* load */
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"));
- }
+ nextpc = thumb_get_next_pc_raw (frame, pc);
else
- {
- nextpc = arm_get_next_pc_raw (frame, pc);
- if (nextpc == pc)
- error (_("Infinite loop detected"));
- }
+ nextpc = arm_get_next_pc_raw (frame, pc);
return nextpc;
}
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
+/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
+ instruction and ending with a STREX{,B,H,D} instruction. If such a sequence
+ is found, attempt to step through it. A breakpoint is placed at the end of
+ the sequence. */
+
+static int
+thumb_deal_with_atomic_sequence_raw (struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ CORE_ADDR pc = get_frame_pc (frame);
+ CORE_ADDR breaks[2] = {-1, -1};
+ CORE_ADDR loc = pc;
+ unsigned short insn1, insn2;
+ int insn_count;
+ int index;
+ int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */
+ const int atomic_sequence_length = 16; /* Instruction sequence length. */
+ ULONGEST status, itstate;
+
+ /* We currently do not support atomic sequences within an IT block. */
+ status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+ itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+ if (itstate & 0x0f)
+ return 0;
+
+ /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction. */
+ insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
+ loc += 2;
+ if (thumb_insn_size (insn1) != 4)
+ return 0;
+
+ insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
+ loc += 2;
+ if (!((insn1 & 0xfff0) == 0xe850
+ || ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040)))
+ return 0;
+
+ /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+ instructions. */
+ for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+ {
+ insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
+ loc += 2;
+
+ if (thumb_insn_size (insn1) != 4)
+ {
+ /* Assume that there is at most one conditional branch in the
+ atomic sequence. If a conditional branch is found, put a
+ breakpoint in its destination address. */
+ if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f)
+ {
+ if (last_breakpoint > 0)
+ return 0; /* More than one conditional branch found,
+ fallback to the standard code. */
+
+ breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1);
+ last_breakpoint++;
+ }
+
+ /* We do not support atomic sequences that use any *other*
+ instructions but conditional branches to change the PC.
+ Fall back to standard code to avoid losing control of
+ execution. */
+ else if (thumb_instruction_changes_pc (insn1))
+ return 0;
+ }
+ else
+ {
+ insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
+ loc += 2;
+
+ /* Assume that there is at most one conditional branch in the
+ atomic sequence. If a conditional branch is found, put a
+ breakpoint in its destination address. */
+ if ((insn1 & 0xf800) == 0xf000
+ && (insn2 & 0xd000) == 0x8000
+ && (insn1 & 0x0380) != 0x0380)
+ {
+ int sign, j1, j2, imm1, imm2;
+ unsigned int offset;
+
+ sign = sbits (insn1, 10, 10);
+ imm1 = bits (insn1, 0, 5);
+ imm2 = bits (insn2, 0, 10);
+ j1 = bit (insn2, 13);
+ j2 = bit (insn2, 11);
+
+ offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+ offset += (imm1 << 12) + (imm2 << 1);
+
+ if (last_breakpoint > 0)
+ return 0; /* More than one conditional branch found,
+ fallback to the standard code. */
+
+ breaks[1] = loc + offset;
+ last_breakpoint++;
+ }
+
+ /* We do not support atomic sequences that use any *other*
+ instructions but conditional branches to change the PC.
+ Fall back to standard code to avoid losing control of
+ execution. */
+ else if (thumb2_instruction_changes_pc (insn1, insn2))
+ return 0;
+
+ /* If we find a strex{,b,h,d}, we're done. */
+ if ((insn1 & 0xfff0) == 0xe840
+ || ((insn1 & 0xfff0) == 0xe8c0 && (insn2 & 0x00c0) == 0x0040))
+ break;
+ }
+ }
+
+ /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence. */
+ if (insn_count == atomic_sequence_length)
+ return 0;
+
+ /* Insert a breakpoint right after the end of the atomic sequence. */
+ breaks[0] = loc;
+
+ /* Check for duplicated breakpoints. Check also for a breakpoint
+ placed (branch instruction's destination) anywhere in sequence. */
+ if (last_breakpoint
+ && (breaks[1] == breaks[0]
+ || (breaks[1] >= pc && breaks[1] < loc)))
+ last_breakpoint = 0;
+
+ /* Effectively inserts the breakpoints. */
+ for (index = 0; index <= last_breakpoint; index++)
+ arm_insert_single_step_breakpoint (gdbarch, aspace,
+ MAKE_THUMB_ADDR (breaks[index]));
+
+ return 1;
+}
+
+static int
+arm_deal_with_atomic_sequence_raw (struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ CORE_ADDR pc = get_frame_pc (frame);
+ CORE_ADDR breaks[2] = {-1, -1};
+ CORE_ADDR loc = pc;
+ unsigned int insn;
+ int insn_count;
+ int index;
+ int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */
+ const int atomic_sequence_length = 16; /* Instruction sequence length. */
+
+ /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.
+ Note that we do not currently support conditionally executed atomic
+ instructions. */
+ insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code);
+ loc += 4;
+ if ((insn & 0xff9000f0) != 0xe1900090)
+ return 0;
+
+ /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+ instructions. */
+ for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+ {
+ insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code);
+ loc += 4;
+
+ /* Assume that there is at most one conditional branch in the atomic
+ sequence. If a conditional branch is found, put a breakpoint in
+ its destination address. */
+ if (bits (insn, 24, 27) == 0xa)
+ {
+ if (last_breakpoint > 0)
+ return 0; /* More than one conditional branch found, fallback
+ to the standard single-step code. */
+
+ breaks[1] = BranchDest (loc - 4, insn);
+ last_breakpoint++;
+ }
+
+ /* We do not support atomic sequences that use any *other* instructions
+ but conditional branches to change the PC. Fall back to standard
+ code to avoid losing control of execution. */
+ else if (arm_instruction_changes_pc (insn))
+ return 0;
+
+ /* If we find a strex{,b,h,d}, we're done. */
+ if ((insn & 0xff9000f0) == 0xe1800090)
+ break;
+ }
+
+ /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence. */
+ if (insn_count == atomic_sequence_length)
+ return 0;
+
+ /* Insert a breakpoint right after the end of the atomic sequence. */
+ breaks[0] = loc;
+
+ /* Check for duplicated breakpoints. Check also for a breakpoint
+ placed (branch instruction's destination) anywhere in sequence. */
+ if (last_breakpoint
+ && (breaks[1] == breaks[0]
+ || (breaks[1] >= pc && breaks[1] < loc)))
+ last_breakpoint = 0;
+
+ /* Effectively inserts the breakpoints. */
+ for (index = 0; index <= last_breakpoint; index++)
+ arm_insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
+
+ return 1;
+}
+
+int
+arm_deal_with_atomic_sequence (struct frame_info *frame)
+{
+ if (arm_frame_is_thumb (frame))
+ return thumb_deal_with_atomic_sequence_raw (frame);
+ else
+ return arm_deal_with_atomic_sequence_raw (frame);
+}
+
+/* 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
and breakpoint it. */
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
- CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+ CORE_ADDR next_pc;
+
+ if (arm_deal_with_atomic_sequence (frame))
+ return 1;
+ next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
int old_len, int new_len)
{
- gdb_byte *new_buf, *middle;
+ gdb_byte *new_buf;
int bytes_to_read = new_len - old_len;
- new_buf = xmalloc (new_len);
+ new_buf = (gdb_byte *) xmalloc (new_len);
memcpy (new_buf + bytes_to_read, buf, old_len);
xfree (buf);
if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
gdb_byte *buf;
char map_type;
CORE_ADDR boundary, func_start;
- int buf_len, buf2_len;
+ int buf_len;
enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
int i, any, last_it, last_it_count;
/* No room for an IT instruction. */
return bpaddr;
- buf = xmalloc (buf_len);
+ buf = (gdb_byte *) xmalloc (buf_len);
if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
return bpaddr;
any = 0;
Preparation: tmp1, tmp2, tmp3 <- r0, r1, r2;
r0, r1, r2 <- rd, rn, rm
- Insn: <op><cond> r0, r1, r2 [, <shift>]
+ Insn: <op><cond> r0, [r1,] r2 [, <shift>]
Cleanup: rd <- r0; r0, r1, r2 <- tmp1, tmp2, tmp3
*/
struct regcache *regs,
struct displaced_step_closure *dsc)
{
- unsigned rn, rm, rd;
+ unsigned rm, rd;
- rd = bits (insn, 3, 6);
- rn = (bit (insn, 7) << 3) | bits (insn, 0, 2);
- rm = 2;
+ rm = bits (insn, 3, 6);
+ rd = (bit (insn, 7) << 3) | bits (insn, 0, 2);
- if (rd != ARM_PC_REGNUM && rn != ARM_PC_REGNUM)
+ if (rd != ARM_PC_REGNUM && rm != ARM_PC_REGNUM)
return thumb_copy_unmodified_16bit (gdbarch, insn, "ALU reg", dsc);
if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.4x\n",
- "ALU", (unsigned short) insn);
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying ALU reg insn %.4x\n",
+ (unsigned short) insn);
- dsc->modinsn[0] = ((insn & 0xff00) | 0x08);
+ dsc->modinsn[0] = ((insn & 0xff00) | 0x10);
- install_alu_reg (gdbarch, regs, dsc, rd, rn, rm);
+ install_alu_reg (gdbarch, regs, dsc, rd, rd, rm);
return 0;
}
struct displaced_step_closure *dsc)
{
uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
- int load_executed = condition_true (dsc->u.block.cond, status), i;
+ int load_executed = condition_true (dsc->u.block.cond, status);
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;
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;
+ const gdb_byte *bkp_insn;
offset = 0;
/* Poke modified instruction(s). */
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
- struct displaced_step_closure *dsc
- = xmalloc (sizeof (struct displaced_step_closure));
+ struct displaced_step_closure *dsc = XNEW (struct displaced_step_closure);
+
arm_process_displaced_insn (gdbarch, from, to, regs, dsc);
arm_displaced_init_closure (gdbarch, from, to, dsc);
static int
gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
{
- struct gdbarch *gdbarch = info->application_data;
+ struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
if (arm_pc_is_thumb (gdbarch, memaddr))
{
#define THUMB_LE_BREAKPOINT {0xbe,0xbe}
#define THUMB_BE_BREAKPOINT {0xbe,0xbe}
-static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
-static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
-static const char arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
-static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
+static const gdb_byte arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
+static const gdb_byte arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
+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
arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
int *kindptr)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
arm_breakpoint_from_pc (gdbarch, pcptr, kindptr);
if (arm_pc_is_thumb (gdbarch, *pcptr) && *kindptr == 4)
int nRc;
enum type_code code;
- CHECK_TYPEDEF (type);
+ type = check_typedef (type);
/* In the ARM ABI, "integer" like aggregate types are returned in
registers. For an aggregate type to be integer like, its size
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
switch (gdbarch_tdep (gdbarch)->fp_model)
{
/* Handle function return values. */
static enum return_value_convention
-arm_return_value (struct gdbarch *gdbarch, struct type *func_type,
+arm_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *valtype, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct type *func_type = function ? value_type (function) : NULL;
enum arm_vfp_cprc_base_type vfp_base_type;
int vfp_base_count;
char name_buf[4];
int regnum;
- sprintf (name_buf, "%c%d", reg_char, i);
+ xsnprintf (name_buf, sizeof (name_buf), "%c%d", reg_char, i);
regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
if (writebuf)
return RETURN_VALUE_STRUCT_CONVENTION;
}
+ /* AAPCS returns complex types longer than a register in memory. */
+ if (tdep->arm_abi != ARM_ABI_APCS
+ && TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
+ && TYPE_LENGTH (valtype) > INT_REGISTER_SIZE)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
if (writebuf)
arm_store_return_value (valtype, regcache, writebuf);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR jb_addr;
- char buf[INT_REGISTER_SIZE];
+ gdb_byte buf[INT_REGISTER_SIZE];
jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
CORE_ADDR
arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
{
- char *name;
+ const char *name;
int namelen;
CORE_ADDR start_addr;
/* Find the starting address and name of the function containing the PC. */
if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
- return 0;
+ {
+ /* Trampoline 'bx reg' doesn't belong to any functions. Do the
+ check here. */
+ start_addr = arm_skip_bx_reg (frame, pc);
+ if (start_addr != 0)
+ return start_addr;
+
+ return 0;
+ }
/* If PC is in a Thumb call or return stub, return the address of the
target PC, which is in a register. The thunk functions are called
_call_via_xx, where x is the register name. The possible names
are r0-r9, sl, fp, ip, sp, and lr. ARM RealView has similar
functions, named __ARM_call_via_r[0-7]. */
- if (strncmp (name, "_call_via_", 10) == 0
- || strncmp (name, "__ARM_call_via_", strlen ("__ARM_call_via_")) == 0)
+ if (startswith (name, "_call_via_")
+ || startswith (name, "__ARM_call_via_"))
{
/* Use the name suffix to determine which register contains the
target PC. */
namelen = strlen (name);
if (name[0] == '_' && name[1] == '_'
&& ((namelen > 2 + strlen ("_from_thumb")
- && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
- strlen ("_from_thumb")) == 0)
+ && startswith (name + namelen - strlen ("_from_thumb"), "_from_thumb"))
|| (namelen > 2 + strlen ("_from_arm")
- && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
- strlen ("_from_arm")) == 0)))
+ && startswith (name + namelen - strlen ("_from_arm"), "_from_arm"))))
{
char *target_name;
int target_len = namelen - 2;
- struct minimal_symbol *minsym;
+ struct bound_minimal_symbol minsym;
struct objfile *objfile;
struct obj_section *sec;
else
target_len -= strlen ("_from_arm");
- target_name = alloca (target_len + 1);
+ target_name = (char *) alloca (target_len + 1);
memcpy (target_name, name + 2, target_len);
target_name[target_len] = '\0';
sec = find_pc_section (pc);
objfile = (sec == NULL) ? NULL : sec->objfile;
minsym = lookup_minimal_symbol (target_name, NULL, objfile);
- if (minsym != NULL)
- return SYMBOL_VALUE_ADDRESS (minsym);
+ if (minsym.minsym != NULL)
+ return BMSYMBOL_VALUE_ADDRESS (minsym);
else
return 0;
}
struct gdbarch_info info;
/* If the current architecture is not ARM, we have nothing to do. */
- if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_arm)
+ if (gdbarch_bfd_arch_info (target_gdbarch ())->arch != bfd_arch_arm)
return;
/* Update the architecture. */
set_fp_model_sfunc (char *args, int from_tty,
struct cmd_list_element *c)
{
- enum arm_float_model fp_model;
+ int fp_model;
for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
{
- arm_fp_model = fp_model;
+ arm_fp_model = (enum arm_float_model) fp_model;
break;
}
show_fp_model (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch ());
if (arm_fp_model == ARM_FLOAT_AUTO
- && gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_arm)
+ && gdbarch_bfd_arch_info (target_gdbarch ())->arch == bfd_arch_arm)
fprintf_filtered (file, _("\
The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
fp_model_strings[tdep->fp_model]);
arm_set_abi (char *args, int from_tty,
struct cmd_list_element *c)
{
- enum arm_abi_kind arm_abi;
+ int arm_abi;
for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
{
- arm_abi_global = arm_abi;
+ arm_abi_global = (enum arm_abi_kind) arm_abi;
break;
}
arm_show_abi (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch ());
if (arm_abi_global == ARM_ABI_AUTO
- && gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_arm)
+ && gdbarch_bfd_arch_info (target_gdbarch ())->arch == bfd_arch_arm)
fprintf_filtered (file, _("\
The current ARM ABI is \"auto\" (currently \"%s\").\n"),
arm_abi_strings[tdep->arm_abi]);
arm_show_fallback_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
-
fprintf_filtered (file,
_("The current execution mode assumed "
"(when symbols are unavailable) is \"%s\".\n"),
arm_show_force_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch ());
fprintf_filtered (file,
_("The current execution mode assumed "
static void
arm_objfile_data_free (struct objfile *objfile, void *arg)
{
- struct arm_per_objfile *data = arg;
+ struct arm_per_objfile *data = (struct arm_per_objfile *) arg;
unsigned int i;
for (i = 0; i < objfile->obfd->section_count; i++)
if (name[1] != 'a' && name[1] != 't' && name[1] != 'd')
return;
- data = objfile_data (objfile, arm_objfile_data_key);
+ data = (struct arm_per_objfile *) objfile_data (objfile,
+ arm_objfile_data_key);
if (data == NULL)
{
data = OBSTACK_ZALLOC (&objfile->objfile_obstack,
int offset, double_regnum;
enum register_status status;
- sprintf (name_buf, "d%d", regnum << 1);
+ xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum << 1);
double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
else
offset = (regnum & 1) ? 4 : 0;
- sprintf (name_buf, "d%d", regnum >> 1);
+ xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum >> 1);
double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
int regnum, const gdb_byte *buf)
{
char name_buf[4];
- gdb_byte reg_buf[8];
int offset, double_regnum;
- sprintf (name_buf, "d%d", regnum << 1);
+ xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum << 1);
double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
else
offset = (regnum & 1) ? 4 : 0;
- sprintf (name_buf, "d%d", regnum >> 1);
+ xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum >> 1);
double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
strlen (name_buf));
static struct value *
value_of_arm_user_reg (struct frame_info *frame, const void *baton)
{
- const int *reg_p = baton;
+ const int *reg_p = (const int *) baton;
return value_of_register (*reg_p, frame);
}
\f
return default_register_reggroup_p (gdbarch, regnum, group);
}
+\f
+/* For backward-compatibility we allow two 'g' packet lengths with
+ the remote protocol depending on whether FPA registers are
+ supplied. M-profile targets do not have FPA registers, but some
+ stubs already exist in the wild which use a 'g' packet which
+ supplies them albeit with dummy values. The packet format which
+ includes FPA registers should be considered deprecated for
+ M-profile targets. */
+
+static void
+arm_register_g_packet_guesses (struct gdbarch *gdbarch)
+{
+ if (gdbarch_tdep (gdbarch)->is_m)
+ {
+ /* If we know from the executable this is an M-profile target,
+ cater for remote targets whose register set layout is the
+ same as the FPA layout. */
+ register_remote_g_packet_guess (gdbarch,
+ /* r0-r12,sp,lr,pc; f0-f7; fps,xpsr */
+ (16 * INT_REGISTER_SIZE)
+ + (8 * FP_REGISTER_SIZE)
+ + (2 * INT_REGISTER_SIZE),
+ tdesc_arm_with_m_fpa_layout);
+
+ /* The regular M-profile layout. */
+ register_remote_g_packet_guess (gdbarch,
+ /* r0-r12,sp,lr,pc; xpsr */
+ (16 * INT_REGISTER_SIZE)
+ + INT_REGISTER_SIZE,
+ tdesc_arm_with_m);
+
+ /* M-profile plus M4F VFP. */
+ register_remote_g_packet_guess (gdbarch,
+ /* r0-r12,sp,lr,pc; d0-d15; fpscr,xpsr */
+ (16 * INT_REGISTER_SIZE)
+ + (16 * VFP_REGISTER_SIZE)
+ + (2 * INT_REGISTER_SIZE),
+ tdesc_arm_with_m_vfp_d16);
+ }
+
+ /* Otherwise we don't have a useful guess. */
+}
+
\f
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
enum arm_float_model fp_model = arm_fp_model;
struct tdesc_arch_data *tdesc_data = NULL;
int i, is_m = 0;
- int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+ int vfp_register_count = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+ int have_wmmx_registers = 0;
int have_neon = 0;
int have_fpa_registers = 1;
const struct target_desc *tdesc = info.target_desc;
anyway, so assume APCS. */
arm_abi = ARM_ABI_APCS;
}
- else if (ei_osabi == ELFOSABI_NONE)
+ else if (ei_osabi == ELFOSABI_NONE || ei_osabi == ELFOSABI_GNU)
{
int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
int attr_arch, attr_profile;
OBJ_ATTR_PROC,
Tag_ABI_VFP_args))
{
- case 0:
+ case AEABI_VFP_args_base:
/* "The user intended FP parameter/result
passing to conform to AAPCS, base
variant". */
fp_model = ARM_FLOAT_SOFT_VFP;
break;
- case 1:
+ case AEABI_VFP_args_vfp:
/* "The user intended FP parameter/result
passing to conform to AAPCS, VFP
variant". */
fp_model = ARM_FLOAT_VFP;
break;
- case 2:
+ case AEABI_VFP_args_toolchain:
/* "The user intended FP parameter/result
passing to conform to tool chain-specific
conventions" - we don't know any such
conventions, so leave it as "auto". */
break;
+ case AEABI_VFP_args_compatible:
+ /* "Code is compatible with both the base
+ and VFP variants; the user did not permit
+ non-variadic functions to pass FP
+ parameters/results" - leave it as
+ "auto". */
+ break;
default:
/* Attribute value not mentioned in the
- October 2008 ABI, so leave it as
+ November 2012 ABI, so leave it as
"auto". */
break;
}
&& (attr_arch == TAG_CPU_ARCH_V6_M
|| attr_arch == TAG_CPU_ARCH_V6S_M
|| attr_profile == 'M'))
- tdesc = tdesc_arm_with_m;
+ is_m = 1;
#endif
}
tdesc_data_cleanup (tdesc_data);
return NULL;
}
+
+ have_wmmx_registers = 1;
}
/* If we have a VFP unit, check whether the single precision registers
if (tdesc_unnumbered_register (feature, "s0") == 0)
have_vfp_pseudos = 1;
- have_vfp_registers = 1;
+ vfp_register_count = i;
/* If we have VFP, also check for NEON. The architecture allows
NEON without VFP (integer vector operations only), but GDB
return best_arch->gdbarch;
}
- tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
/* Record additional information about the architecture we are defining.
tdep->fp_model = fp_model;
tdep->is_m = is_m;
tdep->have_fpa_registers = have_fpa_registers;
- tdep->have_vfp_registers = have_vfp_registers;
+ tdep->have_wmmx_registers = have_wmmx_registers;
+ gdb_assert (vfp_register_count == 0
+ || vfp_register_count == 16
+ || vfp_register_count == 32);
+ tdep->vfp_register_count = vfp_register_count;
tdep->have_vfp_pseudos = have_vfp_pseudos;
tdep->have_neon_pseudos = have_neon_pseudos;
tdep->have_neon = have_neon;
+ arm_register_g_packet_guesses (gdbarch);
+
/* Breakpoints. */
switch (info.byte_order_for_code)
{
frame_base_set_default (gdbarch, &arm_normal_base);
/* Address manipulation. */
- set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
/* Advance PC across function entry code. */
set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
- /* Detect whether PC is in function epilogue. */
- set_gdbarch_in_function_epilogue_p (gdbarch, arm_in_function_epilogue_p);
+ /* Detect whether PC is at a point where the stack has been destroyed. */
+ set_gdbarch_stack_frame_destroyed_p (gdbarch, arm_stack_frame_destroyed_p);
/* Skip trampolines. */
set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
dwarf2_frame_set_init_reg (gdbarch, arm_dwarf2_frame_init_reg);
/* Add some default predicates. */
+ if (is_m)
+ frame_unwind_append_unwinder (gdbarch, &arm_m_exception_unwind);
frame_unwind_append_unwinder (gdbarch, &arm_stub_unwind);
dwarf2_append_unwinders (gdbarch);
frame_unwind_append_unwinder (gdbarch, &arm_exidx_unwind);
/* Initialize the standard target descriptions. */
initialize_tdesc_arm_with_m ();
+ initialize_tdesc_arm_with_m_fpa_layout ();
+ initialize_tdesc_arm_with_m_vfp_d16 ();
initialize_tdesc_arm_with_iwmmxt ();
initialize_tdesc_arm_with_vfpv2 ();
initialize_tdesc_arm_with_vfpv3 ();
/* Initialize the array that will be passed to
add_setshow_enum_cmd(). */
- valid_disassembly_styles
- = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
+ valid_disassembly_styles = XNEWVEC (const char *,
+ num_disassembly_options + 1);
for (i = 0; i < num_disassembly_options; i++)
{
numregs = get_arm_regnames (i, &setname, &setdesc, ®names);
NULL, /* FIXME: i18n: "ARM debugging is %s. */
&setdebuglist, &showdebuglist);
}
+
+/* ARM-reversible process record data structures. */
+
+#define ARM_INSN_SIZE_BYTES 4
+#define THUMB_INSN_SIZE_BYTES 2
+#define THUMB2_INSN_SIZE_BYTES 4
+
+
+/* Position of the bit within a 32-bit ARM instruction
+ that defines whether the instruction is a load or store. */
+#define INSN_S_L_BIT_NUM 20
+
+#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \
+ do \
+ { \
+ unsigned int reg_len = LENGTH; \
+ if (reg_len) \
+ { \
+ REGS = XNEWVEC (uint32_t, reg_len); \
+ memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \
+ } \
+ } \
+ while (0)
+
+#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \
+ do \
+ { \
+ unsigned int mem_len = LENGTH; \
+ if (mem_len) \
+ { \
+ MEMS = XNEWVEC (struct arm_mem_r, mem_len); \
+ memcpy(&MEMS->len, &RECORD_BUF[0], \
+ sizeof(struct arm_mem_r) * LENGTH); \
+ } \
+ } \
+ while (0)
+
+/* Checks whether insn is already recorded or yet to be decoded. (boolean expression). */
+#define INSN_RECORDED(ARM_RECORD) \
+ (0 != (ARM_RECORD)->reg_rec_count || 0 != (ARM_RECORD)->mem_rec_count)
+
+/* ARM memory record structure. */
+struct arm_mem_r
+{
+ uint32_t len; /* Record length. */
+ uint32_t addr; /* Memory address. */
+};
+
+/* ARM instruction record contains opcode of current insn
+ and execution state (before entry to decode_insn()),
+ contains list of to-be-modified registers and
+ memory blocks (on return from decode_insn()). */
+
+typedef struct insn_decode_record_t
+{
+ struct gdbarch *gdbarch;
+ struct regcache *regcache;
+ CORE_ADDR this_addr; /* Address of the insn being decoded. */
+ uint32_t arm_insn; /* Should accommodate thumb. */
+ uint32_t cond; /* Condition code. */
+ uint32_t opcode; /* Insn opcode. */
+ uint32_t decode; /* Insn decode bits. */
+ uint32_t mem_rec_count; /* No of mem records. */
+ uint32_t reg_rec_count; /* No of reg records. */
+ uint32_t *arm_regs; /* Registers to be saved for this record. */
+ struct arm_mem_r *arm_mems; /* Memory to be saved for this record. */
+} insn_decode_record;
+
+
+/* Checks ARM SBZ and SBO mandatory fields. */
+
+static int
+sbo_sbz (uint32_t insn, uint32_t bit_num, uint32_t len, uint32_t sbo)
+{
+ uint32_t ones = bits (insn, bit_num - 1, (bit_num -1) + (len - 1));
+
+ if (!len)
+ return 1;
+
+ if (!sbo)
+ ones = ~ones;
+
+ while (ones)
+ {
+ if (!(ones & sbo))
+ {
+ return 0;
+ }
+ ones = ones >> 1;
+ }
+ return 1;
+}
+
+enum arm_record_result
+{
+ ARM_RECORD_SUCCESS = 0,
+ ARM_RECORD_FAILURE = 1
+};
+
+typedef enum
+{
+ ARM_RECORD_STRH=1,
+ ARM_RECORD_STRD
+} arm_record_strx_t;
+
+typedef enum
+{
+ ARM_RECORD=1,
+ THUMB_RECORD,
+ THUMB2_RECORD
+} record_type_t;
+
+
+static int
+arm_record_strx (insn_decode_record *arm_insn_r, uint32_t *record_buf,
+ uint32_t *record_buf_mem, arm_record_strx_t str_type)
+{
+
+ struct regcache *reg_cache = arm_insn_r->regcache;
+ ULONGEST u_regval[2]= {0};
+
+ uint32_t reg_src1 = 0, reg_src2 = 0;
+ uint32_t immed_high = 0, immed_low = 0,offset_8 = 0, tgt_mem_addr = 0;
+ uint32_t opcode1 = 0;
+
+ arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
+ arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
+ opcode1 = bits (arm_insn_r->arm_insn, 20, 24);
+
+
+ if (14 == arm_insn_r->opcode || 10 == arm_insn_r->opcode)
+ {
+ /* 1) Handle misc store, immediate offset. */
+ immed_low = bits (arm_insn_r->arm_insn, 0, 3);
+ immed_high = bits (arm_insn_r->arm_insn, 8, 11);
+ reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1,
+ &u_regval[0]);
+ if (ARM_PC_REGNUM == reg_src1)
+ {
+ /* If R15 was used as Rn, hence current PC+8. */
+ u_regval[0] = u_regval[0] + 8;
+ }
+ offset_8 = (immed_high << 4) | immed_low;
+ /* Calculate target store address. */
+ if (14 == arm_insn_r->opcode)
+ {
+ tgt_mem_addr = u_regval[0] + offset_8;
+ }
+ else
+ {
+ tgt_mem_addr = u_regval[0] - offset_8;
+ }
+ if (ARM_RECORD_STRH == str_type)
+ {
+ record_buf_mem[0] = 2;
+ record_buf_mem[1] = tgt_mem_addr;
+ arm_insn_r->mem_rec_count = 1;
+ }
+ else if (ARM_RECORD_STRD == str_type)
+ {
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = tgt_mem_addr;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = tgt_mem_addr + 4;
+ arm_insn_r->mem_rec_count = 2;
+ }
+ }
+ else if (12 == arm_insn_r->opcode || 8 == arm_insn_r->opcode)
+ {
+ /* 2) Store, register offset. */
+ /* Get Rm. */
+ reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
+ /* Get Rn. */
+ reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
+ if (15 == reg_src2)
+ {
+ /* If R15 was used as Rn, hence current PC+8. */
+ u_regval[0] = u_regval[0] + 8;
+ }
+ /* Calculate target store address, Rn +/- Rm, register offset. */
+ if (12 == arm_insn_r->opcode)
+ {
+ tgt_mem_addr = u_regval[0] + u_regval[1];
+ }
+ else
+ {
+ tgt_mem_addr = u_regval[1] - u_regval[0];
+ }
+ if (ARM_RECORD_STRH == str_type)
+ {
+ record_buf_mem[0] = 2;
+ record_buf_mem[1] = tgt_mem_addr;
+ arm_insn_r->mem_rec_count = 1;
+ }
+ else if (ARM_RECORD_STRD == str_type)
+ {
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = tgt_mem_addr;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = tgt_mem_addr + 4;
+ arm_insn_r->mem_rec_count = 2;
+ }
+ }
+ else if (11 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
+ || 2 == arm_insn_r->opcode || 6 == arm_insn_r->opcode)
+ {
+ /* 3) Store, immediate pre-indexed. */
+ /* 5) Store, immediate post-indexed. */
+ immed_low = bits (arm_insn_r->arm_insn, 0, 3);
+ immed_high = bits (arm_insn_r->arm_insn, 8, 11);
+ offset_8 = (immed_high << 4) | immed_low;
+ reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ /* Calculate target store address, Rn +/- Rm, register offset. */
+ if (15 == arm_insn_r->opcode || 6 == arm_insn_r->opcode)
+ {
+ tgt_mem_addr = u_regval[0] + offset_8;
+ }
+ else
+ {
+ tgt_mem_addr = u_regval[0] - offset_8;
+ }
+ if (ARM_RECORD_STRH == str_type)
+ {
+ record_buf_mem[0] = 2;
+ record_buf_mem[1] = tgt_mem_addr;
+ arm_insn_r->mem_rec_count = 1;
+ }
+ else if (ARM_RECORD_STRD == str_type)
+ {
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = tgt_mem_addr;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = tgt_mem_addr + 4;
+ arm_insn_r->mem_rec_count = 2;
+ }
+ /* Record Rn also as it changes. */
+ *(record_buf) = bits (arm_insn_r->arm_insn, 16, 19);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (9 == arm_insn_r->opcode || 13 == arm_insn_r->opcode
+ || 0 == arm_insn_r->opcode || 4 == arm_insn_r->opcode)
+ {
+ /* 4) Store, register pre-indexed. */
+ /* 6) Store, register post -indexed. */
+ reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
+ reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
+ /* Calculate target store address, Rn +/- Rm, register offset. */
+ if (13 == arm_insn_r->opcode || 4 == arm_insn_r->opcode)
+ {
+ tgt_mem_addr = u_regval[0] + u_regval[1];
+ }
+ else
+ {
+ tgt_mem_addr = u_regval[1] - u_regval[0];
+ }
+ if (ARM_RECORD_STRH == str_type)
+ {
+ record_buf_mem[0] = 2;
+ record_buf_mem[1] = tgt_mem_addr;
+ arm_insn_r->mem_rec_count = 1;
+ }
+ else if (ARM_RECORD_STRD == str_type)
+ {
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = tgt_mem_addr;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = tgt_mem_addr + 4;
+ arm_insn_r->mem_rec_count = 2;
+ }
+ /* Record Rn also as it changes. */
+ *(record_buf) = bits (arm_insn_r->arm_insn, 16, 19);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ return 0;
+}
+
+/* Handling ARM extension space insns. */
+
+static int
+arm_record_extension_space (insn_decode_record *arm_insn_r)
+{
+ uint32_t ret = 0; /* Return value: -1:record failure ; 0:success */
+ uint32_t opcode1 = 0, opcode2 = 0, insn_op1 = 0;
+ uint32_t record_buf[8], record_buf_mem[8];
+ uint32_t reg_src1 = 0;
+ uint32_t immed_high = 0, immed_low = 0,offset_8 = 0, tgt_mem_addr = 0;
+ struct regcache *reg_cache = arm_insn_r->regcache;
+ ULONGEST u_regval = 0;
+
+ gdb_assert (!INSN_RECORDED(arm_insn_r));
+ /* Handle unconditional insn extension space. */
+
+ opcode1 = bits (arm_insn_r->arm_insn, 20, 27);
+ opcode2 = bits (arm_insn_r->arm_insn, 4, 7);
+ if (arm_insn_r->cond)
+ {
+ /* PLD has no affect on architectural state, it just affects
+ the caches. */
+ if (5 == ((opcode1 & 0xE0) >> 5))
+ {
+ /* BLX(1) */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ /* STC2, LDC2, MCR2, MRC2, CDP2: <TBD>, co-processor insn. */
+ }
+
+
+ opcode1 = bits (arm_insn_r->arm_insn, 25, 27);
+ if (3 == opcode1 && bit (arm_insn_r->arm_insn, 4))
+ {
+ ret = -1;
+ /* Undefined instruction on ARM V5; need to handle if later
+ versions define it. */
+ }
+
+ opcode1 = bits (arm_insn_r->arm_insn, 24, 27);
+ opcode2 = bits (arm_insn_r->arm_insn, 4, 7);
+ insn_op1 = bits (arm_insn_r->arm_insn, 20, 23);
+
+ /* Handle arithmetic insn extension space. */
+ if (!opcode1 && 9 == opcode2 && 1 != arm_insn_r->cond
+ && !INSN_RECORDED(arm_insn_r))
+ {
+ /* Handle MLA(S) and MUL(S). */
+ if (0 <= insn_op1 && 3 >= insn_op1)
+ {
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (4 <= insn_op1 && 15 >= insn_op1)
+ {
+ /* Handle SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 16, 19);
+ record_buf[1] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[2] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 3;
+ }
+ }
+
+ opcode1 = bits (arm_insn_r->arm_insn, 26, 27);
+ opcode2 = bits (arm_insn_r->arm_insn, 23, 24);
+ insn_op1 = bits (arm_insn_r->arm_insn, 21, 22);
+
+ /* Handle control insn extension space. */
+
+ if (!opcode1 && 2 == opcode2 && !bit (arm_insn_r->arm_insn, 20)
+ && 1 != arm_insn_r->cond && !INSN_RECORDED(arm_insn_r))
+ {
+ if (!bit (arm_insn_r->arm_insn,25))
+ {
+ if (!bits (arm_insn_r->arm_insn, 4, 7))
+ {
+ if ((0 == insn_op1) || (2 == insn_op1))
+ {
+ /* MRS. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == insn_op1)
+ {
+ /* CSPR is going to be changed. */
+ record_buf[0] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (3 == insn_op1)
+ {
+ /* 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;
+ }
+ }
+ else if (1 == bits (arm_insn_r->arm_insn, 4, 7))
+ {
+ if (1 == insn_op1)
+ {
+ /* BX. */
+ record_buf[0] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (3 == insn_op1)
+ {
+ /* CLZ. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ else if (3 == bits (arm_insn_r->arm_insn, 4, 7))
+ {
+ /* BLX. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (5 == bits (arm_insn_r->arm_insn, 4, 7))
+ {
+ /* QADD, QSUB, QDADD, QDSUB */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (7 == bits (arm_insn_r->arm_insn, 4, 7))
+ {
+ /* BKPT. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ 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)
+ || 10 == bits (arm_insn_r->arm_insn, 4, 7)
+ || 12 == bits (arm_insn_r->arm_insn, 4, 7)
+ || 14 == bits (arm_insn_r->arm_insn, 4, 7)
+ )
+ {
+ if (0 == insn_op1 || 1 == insn_op1)
+ {
+ /* SMLA<x><y>, SMLAW<y>, SMULW<y>. */
+ /* We dont do optimization for SMULW<y> where we
+ need only Rd. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (2 == insn_op1)
+ {
+ /* SMLAL<x><y>. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (3 == insn_op1)
+ {
+ /* SMUL<x><y>. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ }
+ else
+ {
+ /* MSR : immediate form. */
+ if (1 == insn_op1)
+ {
+ /* CSPR is going to be changed. */
+ record_buf[0] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (3 == insn_op1)
+ {
+ /* 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;
+ }
+ }
+ }
+
+ opcode1 = bits (arm_insn_r->arm_insn, 25, 27);
+ opcode2 = bits (arm_insn_r->arm_insn, 20, 24);
+ insn_op1 = bits (arm_insn_r->arm_insn, 5, 6);
+
+ /* Handle load/store insn extension space. */
+
+ if (!opcode1 && bit (arm_insn_r->arm_insn, 7)
+ && bit (arm_insn_r->arm_insn, 4) && 1 != arm_insn_r->cond
+ && !INSN_RECORDED(arm_insn_r))
+ {
+ /* SWP/SWPB. */
+ if (0 == insn_op1)
+ {
+ /* These insn, changes register and memory as well. */
+ /* SWP or SWPB insn. */
+ /* Get memory address given by Rn. */
+ reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
+ /* SWP insn ?, swaps word. */
+ if (8 == arm_insn_r->opcode)
+ {
+ record_buf_mem[0] = 4;
+ }
+ else
+ {
+ /* SWPB insn, swaps only byte. */
+ record_buf_mem[0] = 1;
+ }
+ record_buf_mem[1] = u_regval;
+ arm_insn_r->mem_rec_count = 1;
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == insn_op1 && !bit (arm_insn_r->arm_insn, 20))
+ {
+ /* STRH. */
+ arm_record_strx(arm_insn_r, &record_buf[0], &record_buf_mem[0],
+ ARM_RECORD_STRH);
+ }
+ else if (2 == insn_op1 && !bit (arm_insn_r->arm_insn, 20))
+ {
+ /* LDRD. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = record_buf[0] + 1;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (3 == insn_op1 && !bit (arm_insn_r->arm_insn, 20))
+ {
+ /* STRD. */
+ arm_record_strx(arm_insn_r, &record_buf[0], &record_buf_mem[0],
+ ARM_RECORD_STRD);
+ }
+ else if (bit (arm_insn_r->arm_insn, 20) && insn_op1 <= 3)
+ {
+ /* LDRH, LDRSB, LDRSH. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+
+ }
+
+ opcode1 = bits (arm_insn_r->arm_insn, 23, 27);
+ if (24 == opcode1 && bit (arm_insn_r->arm_insn, 21)
+ && !INSN_RECORDED(arm_insn_r))
+ {
+ ret = -1;
+ /* Handle coprocessor insn extension space. */
+ }
+
+ /* 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));
+
+
+ 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);
+
+ return ret;
+}
+
+/* Handling opcode 000 insns. */
+
+static int
+arm_record_data_proc_misc_ld_str (insn_decode_record *arm_insn_r)
+{
+ struct regcache *reg_cache = arm_insn_r->regcache;
+ uint32_t record_buf[8], record_buf_mem[8];
+ ULONGEST u_regval[2] = {0};
+
+ uint32_t reg_src1 = 0, reg_src2 = 0, reg_dest = 0;
+ uint32_t immed_high = 0, immed_low = 0, offset_8 = 0, tgt_mem_addr = 0;
+ uint32_t opcode1 = 0;
+
+ arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
+ arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
+ opcode1 = bits (arm_insn_r->arm_insn, 20, 24);
+
+ /* Data processing insn /multiply insn. */
+ if (9 == arm_insn_r->decode
+ && ((4 <= arm_insn_r->opcode && 7 >= arm_insn_r->opcode)
+ || (0 == arm_insn_r->opcode || 1 == arm_insn_r->opcode)))
+ {
+ /* Handle multiply instructions. */
+ /* MLA, MUL, SMLAL, SMULL, UMLAL, UMULL. */
+ if (0 == arm_insn_r->opcode || 1 == arm_insn_r->opcode)
+ {
+ /* Handle MLA and MUL. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 16, 19);
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else if (4 <= arm_insn_r->opcode && 7 >= arm_insn_r->opcode)
+ {
+ /* Handle SMLAL, SMULL, UMLAL, UMULL. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 16, 19);
+ record_buf[1] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[2] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 3;
+ }
+ }
+ else if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)
+ && (11 == arm_insn_r->decode || 13 == arm_insn_r->decode))
+ {
+ /* Handle misc load insns, as 20th bit (L = 1). */
+ /* LDR insn has a capability to do branching, if
+ MOV LR, PC is precceded by LDR insn having Rn as R15
+ in that case, it emulates branch and link insn, and hence we
+ need to save CSPR and PC as well. I am not sure this is right
+ place; as opcode = 010 LDR insn make this happen, if R15 was
+ used. */
+ reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
+ if (15 != reg_dest)
+ {
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ record_buf[0] = reg_dest;
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ }
+ else if ((9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode)
+ && sbo_sbz (arm_insn_r->arm_insn, 5, 12, 0)
+ && sbo_sbz (arm_insn_r->arm_insn, 13, 4, 1)
+ && 2 == bits (arm_insn_r->arm_insn, 20, 21))
+ {
+ /* Handle MSR insn. */
+ if (9 == arm_insn_r->opcode)
+ {
+ /* CSPR is going to be changed. */
+ record_buf[0] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ /* 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;
+ }
+ }
+ else if (9 == arm_insn_r->decode
+ && (8 == arm_insn_r->opcode || 10 == arm_insn_r->opcode)
+ && !bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* Handling SWP, SWPB. */
+ /* These insn, changes register and memory as well. */
+ /* SWP or SWPB insn. */
+
+ reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ /* SWP insn ?, swaps word. */
+ if (8 == arm_insn_r->opcode)
+ {
+ record_buf_mem[0] = 4;
+ }
+ else
+ {
+ /* SWPB insn, swaps only byte. */
+ record_buf_mem[0] = 1;
+ }
+ record_buf_mem[1] = u_regval[0];
+ arm_insn_r->mem_rec_count = 1;
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (3 == arm_insn_r->decode && 0x12 == opcode1
+ && sbo_sbz (arm_insn_r->arm_insn, 9, 12, 1))
+ {
+ /* Handle BLX, branch and link/exchange. */
+ if (9 == arm_insn_r->opcode)
+ {
+ /* Branch is chosen by setting T bit of CSPR, bitp[0] of Rm,
+ and R14 stores the return address. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ }
+ else if (7 == arm_insn_r->decode && 0x12 == opcode1)
+ {
+ /* Handle enhanced software breakpoint insn, BKPT. */
+ /* CPSR is changed to be executed in ARM state, disabling normal
+ interrupts, entering abort mode. */
+ /* According to high vector configuration PC is set. */
+ /* user hit breakpoint and type reverse, in
+ that case, we need to go back with previous CPSR and
+ Program Counter. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ 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
+ && !bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* Handle enhanced store insns and DSP insns (e.g. LDRD). */
+
+ /* Handle str(x) insn */
+ arm_record_strx(arm_insn_r, &record_buf[0], &record_buf_mem[0],
+ ARM_RECORD_STRH);
+ }
+ else if (1 == arm_insn_r->decode && 0x12 == opcode1
+ && sbo_sbz (arm_insn_r->arm_insn, 9, 12, 1))
+ {
+ /* Handle BX, branch and link/exchange. */
+ /* Branch is chosen by setting T bit of CSPR, bitp[0] of Rm. */
+ record_buf[0] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == arm_insn_r->decode && 0x16 == opcode1
+ && sbo_sbz (arm_insn_r->arm_insn, 9, 4, 1)
+ && sbo_sbz (arm_insn_r->arm_insn, 17, 4, 1))
+ {
+ /* Count leading zeros: CLZ. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (!bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)
+ && (8 == arm_insn_r->opcode || 10 == arm_insn_r->opcode)
+ && sbo_sbz (arm_insn_r->arm_insn, 17, 4, 1)
+ && sbo_sbz (arm_insn_r->arm_insn, 1, 12, 0)
+ )
+ {
+ /* Handle MRS insn. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (arm_insn_r->opcode <= 15)
+ {
+ /* Normal data processing insns. */
+ /* Out of 11 shifter operands mode, all the insn modifies destination
+ register, which is specified by 13-16 decode. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else
+ {
+ return -1;
+ }
+
+ 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);
+ return 0;
+}
+
+/* Handling opcode 001 insns. */
+
+static int
+arm_record_data_proc_imm (insn_decode_record *arm_insn_r)
+{
+ uint32_t record_buf[8], record_buf_mem[8];
+
+ arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
+ arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
+
+ if ((9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode)
+ && 2 == bits (arm_insn_r->arm_insn, 20, 21)
+ && sbo_sbz (arm_insn_r->arm_insn, 13, 4, 1)
+ )
+ {
+ /* Handle MSR insn. */
+ if (9 == arm_insn_r->opcode)
+ {
+ /* CSPR is going to be changed. */
+ record_buf[0] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ /* SPSR is going to be changed. */
+ }
+ }
+ else if (arm_insn_r->opcode <= 15)
+ {
+ /* Normal data processing insns. */
+ /* Out of 11 shifter operands mode, all the insn modifies destination
+ register, which is specified by 13-16 decode. */
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else
+ {
+ return -1;
+ }
+
+ 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);
+ return 0;
+}
+
+/* Handle ARM mode instructions with opcode 010. */
+
+static int
+arm_record_ld_st_imm_offset (insn_decode_record *arm_insn_r)
+{
+ struct regcache *reg_cache = arm_insn_r->regcache;
+
+ uint32_t reg_base , reg_dest;
+ uint32_t offset_12, tgt_mem_addr;
+ uint32_t record_buf[8], record_buf_mem[8];
+ unsigned char wback;
+ ULONGEST u_regval;
+
+ /* Calculate wback. */
+ wback = (bit (arm_insn_r->arm_insn, 24) == 0)
+ || (bit (arm_insn_r->arm_insn, 21) == 1);
+
+ arm_insn_r->reg_rec_count = 0;
+ reg_base = bits (arm_insn_r->arm_insn, 16, 19);
+
+ if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* LDR (immediate), LDR (literal), LDRB (immediate), LDRB (literal), LDRBT
+ and LDRT. */
+
+ reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[arm_insn_r->reg_rec_count++] = reg_dest;
+
+ /* The LDR instruction is capable of doing branching. If MOV LR, PC
+ preceeds a LDR instruction having R15 as reg_base, it
+ emulates a branch and link instruction, and hence we need to save
+ CPSR and PC as well. */
+ if (ARM_PC_REGNUM == reg_dest)
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
+ }
+ else
+ {
+ /* STR (immediate), STRB (immediate), STRBT and STRT. */
+
+ offset_12 = bits (arm_insn_r->arm_insn, 0, 11);
+ regcache_raw_read_unsigned (reg_cache, reg_base, &u_regval);
+
+ /* Handle bit U. */
+ if (bit (arm_insn_r->arm_insn, 23))
+ {
+ /* U == 1: Add the offset. */
+ tgt_mem_addr = (uint32_t) u_regval + offset_12;
+ }
+ else
+ {
+ /* U == 0: subtract the offset. */
+ tgt_mem_addr = (uint32_t) u_regval - offset_12;
+ }
+
+ /* Bit 22 tells us whether the store instruction writes 1 byte or 4
+ bytes. */
+ if (bit (arm_insn_r->arm_insn, 22))
+ {
+ /* STRB and STRBT: 1 byte. */
+ record_buf_mem[0] = 1;
+ }
+ else
+ {
+ /* STR and STRT: 4 bytes. */
+ record_buf_mem[0] = 4;
+ }
+
+ /* Handle bit P. */
+ if (bit (arm_insn_r->arm_insn, 24))
+ record_buf_mem[1] = tgt_mem_addr;
+ else
+ record_buf_mem[1] = (uint32_t) u_regval;
+
+ arm_insn_r->mem_rec_count = 1;
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
+ }
+
+ 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);
+ return 0;
+}
+
+/* Handling opcode 011 insns. */
+
+static int
+arm_record_ld_st_reg_offset (insn_decode_record *arm_insn_r)
+{
+ struct regcache *reg_cache = arm_insn_r->regcache;
+
+ uint32_t shift_imm = 0;
+ uint32_t reg_src1 = 0, reg_src2 = 0, reg_dest = 0;
+ uint32_t offset_12 = 0, tgt_mem_addr = 0;
+ uint32_t record_buf[8], record_buf_mem[8];
+
+ LONGEST s_word;
+ ULONGEST u_regval[2];
+
+ arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
+ arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
+
+ /* Handle enhanced store insns and LDRD DSP insn,
+ order begins according to addressing modes for store insns
+ STRH insn. */
+
+ /* LDR or STR? */
+ if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
+ /* LDR insn has a capability to do branching, if
+ MOV LR, PC is precedded by LDR insn having Rn as R15
+ in that case, it emulates branch and link insn, and hence we
+ need to save CSPR and PC as well. */
+ if (15 != reg_dest)
+ {
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ record_buf[0] = reg_dest;
+ record_buf[1] = ARM_PS_REGNUM;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ }
+ else
+ {
+ if (! bits (arm_insn_r->arm_insn, 4, 11))
+ {
+ /* Store insn, register offset and register pre-indexed,
+ register post-indexed. */
+ /* Get Rm. */
+ reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
+ /* Get Rn. */
+ reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_src1
+ , &u_regval[0]);
+ regcache_raw_read_unsigned (reg_cache, reg_src2
+ , &u_regval[1]);
+ if (15 == reg_src2)
+ {
+ /* If R15 was used as Rn, hence current PC+8. */
+ /* Pre-indexed mode doesnt reach here ; illegal insn. */
+ u_regval[0] = u_regval[0] + 8;
+ }
+ /* Calculate target store address, Rn +/- Rm, register offset. */
+ /* U == 1. */
+ if (bit (arm_insn_r->arm_insn, 23))
+ {
+ tgt_mem_addr = u_regval[0] + u_regval[1];
+ }
+ else
+ {
+ tgt_mem_addr = u_regval[1] - u_regval[0];
+ }
+
+ switch (arm_insn_r->opcode)
+ {
+ /* STR. */
+ case 8:
+ case 12:
+ /* STR. */
+ case 9:
+ case 13:
+ /* STRT. */
+ case 1:
+ case 5:
+ /* STR. */
+ case 0:
+ case 4:
+ record_buf_mem[0] = 4;
+ break;
+
+ /* STRB. */
+ case 10:
+ case 14:
+ /* STRB. */
+ case 11:
+ case 15:
+ /* STRBT. */
+ case 3:
+ case 7:
+ /* STRB. */
+ case 2:
+ case 6:
+ record_buf_mem[0] = 1;
+ break;
+
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+ record_buf_mem[1] = tgt_mem_addr;
+ arm_insn_r->mem_rec_count = 1;
+
+ if (9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode
+ || 13 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
+ || 0 == arm_insn_r->opcode || 2 == arm_insn_r->opcode
+ || 4 == arm_insn_r->opcode || 6 == arm_insn_r->opcode
+ || 1 == arm_insn_r->opcode || 3 == arm_insn_r->opcode
+ || 5 == arm_insn_r->opcode || 7 == arm_insn_r->opcode
+ )
+ {
+ /* Rn is going to be changed in pre-indexed mode and
+ post-indexed mode as well. */
+ record_buf[0] = reg_src2;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ else
+ {
+ /* Store insn, scaled register offset; scaled pre-indexed. */
+ offset_12 = bits (arm_insn_r->arm_insn, 5, 6);
+ /* Get Rm. */
+ reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
+ /* Get Rn. */
+ reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
+ /* Get shift_imm. */
+ shift_imm = bits (arm_insn_r->arm_insn, 7, 11);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ regcache_raw_read_signed (reg_cache, reg_src1, &s_word);
+ regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
+ /* Offset_12 used as shift. */
+ switch (offset_12)
+ {
+ case 0:
+ /* Offset_12 used as index. */
+ offset_12 = u_regval[0] << shift_imm;
+ break;
+
+ case 1:
+ offset_12 = (!shift_imm)?0:u_regval[0] >> shift_imm;
+ break;
+
+ case 2:
+ if (!shift_imm)
+ {
+ if (bit (u_regval[0], 31))
+ {
+ offset_12 = 0xFFFFFFFF;
+ }
+ else
+ {
+ offset_12 = 0;
+ }
+ }
+ else
+ {
+ /* This is arithmetic shift. */
+ offset_12 = s_word >> shift_imm;
+ }
+ break;
+
+ case 3:
+ if (!shift_imm)
+ {
+ regcache_raw_read_unsigned (reg_cache, ARM_PS_REGNUM,
+ &u_regval[1]);
+ /* Get C flag value and shift it by 31. */
+ offset_12 = (((bit (u_regval[1], 29)) << 31) \
+ | (u_regval[0]) >> 1);
+ }
+ else
+ {
+ offset_12 = (u_regval[0] >> shift_imm) \
+ | (u_regval[0] <<
+ (sizeof(uint32_t) - shift_imm));
+ }
+ break;
+
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+
+ regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
+ /* bit U set. */
+ if (bit (arm_insn_r->arm_insn, 23))
+ {
+ tgt_mem_addr = u_regval[1] + offset_12;
+ }
+ else
+ {
+ tgt_mem_addr = u_regval[1] - offset_12;
+ }
+
+ switch (arm_insn_r->opcode)
+ {
+ /* STR. */
+ case 8:
+ case 12:
+ /* STR. */
+ case 9:
+ case 13:
+ /* STRT. */
+ case 1:
+ case 5:
+ /* STR. */
+ case 0:
+ case 4:
+ record_buf_mem[0] = 4;
+ break;
+
+ /* STRB. */
+ case 10:
+ case 14:
+ /* STRB. */
+ case 11:
+ case 15:
+ /* STRBT. */
+ case 3:
+ case 7:
+ /* STRB. */
+ case 2:
+ case 6:
+ record_buf_mem[0] = 1;
+ break;
+
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+ record_buf_mem[1] = tgt_mem_addr;
+ arm_insn_r->mem_rec_count = 1;
+
+ if (9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode
+ || 13 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
+ || 0 == arm_insn_r->opcode || 2 == arm_insn_r->opcode
+ || 4 == arm_insn_r->opcode || 6 == arm_insn_r->opcode
+ || 1 == arm_insn_r->opcode || 3 == arm_insn_r->opcode
+ || 5 == arm_insn_r->opcode || 7 == arm_insn_r->opcode
+ )
+ {
+ /* Rn is going to be changed in register scaled pre-indexed
+ mode,and scaled post indexed mode. */
+ record_buf[0] = reg_src2;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ }
+
+ 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);
+ return 0;
+}
+
+/* Handle ARM mode instructions with opcode 100. */
+
+static int
+arm_record_ld_st_multiple (insn_decode_record *arm_insn_r)
+{
+ struct regcache *reg_cache = arm_insn_r->regcache;
+ uint32_t register_count = 0, register_bits;
+ uint32_t reg_base, addr_mode;
+ uint32_t record_buf[24], record_buf_mem[48];
+ uint32_t wback;
+ ULONGEST u_regval;
+
+ /* Fetch the list of registers. */
+ register_bits = bits (arm_insn_r->arm_insn, 0, 15);
+ arm_insn_r->reg_rec_count = 0;
+
+ /* Fetch the base register that contains the address we are loading data
+ to. */
+ reg_base = bits (arm_insn_r->arm_insn, 16, 19);
+
+ /* Calculate wback. */
+ wback = (bit (arm_insn_r->arm_insn, 21) == 1);
+
+ if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* LDM/LDMIA/LDMFD, LDMDA/LDMFA, LDMDB and LDMIB. */
+
+ /* Find out which registers are going to be loaded from memory. */
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ record_buf[arm_insn_r->reg_rec_count++] = register_count;
+ register_bits = register_bits >> 1;
+ register_count++;
+ }
+
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
+
+ /* Save the CPSR register. */
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
+ }
+ else
+ {
+ /* STM (STMIA, STMEA), STMDA (STMED), STMDB (STMFD) and STMIB (STMFA). */
+
+ addr_mode = bits (arm_insn_r->arm_insn, 23, 24);
+
+ regcache_raw_read_unsigned (reg_cache, reg_base, &u_regval);
+
+ /* Find out how many registers are going to be stored to memory. */
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
+
+ switch (addr_mode)
+ {
+ /* STMDA (STMED): Decrement after. */
+ case 0:
+ record_buf_mem[1] = (uint32_t) u_regval
+ - register_count * INT_REGISTER_SIZE + 4;
+ break;
+ /* STM (STMIA, STMEA): Increment after. */
+ case 1:
+ record_buf_mem[1] = (uint32_t) u_regval;
+ break;
+ /* STMDB (STMFD): Decrement before. */
+ case 2:
+ record_buf_mem[1] = (uint32_t) u_regval
+ - register_count * INT_REGISTER_SIZE;
+ break;
+ /* STMIB (STMFA): Increment before. */
+ case 3:
+ record_buf_mem[1] = (uint32_t) u_regval + INT_REGISTER_SIZE;
+ break;
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+
+ record_buf_mem[0] = register_count * INT_REGISTER_SIZE;
+ arm_insn_r->mem_rec_count = 1;
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
+ }
+
+ 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);
+ return 0;
+}
+
+/* Handling opcode 101 insns. */
+
+static int
+arm_record_b_bl (insn_decode_record *arm_insn_r)
+{
+ uint32_t record_buf[8];
+
+ /* Handle B, BL, BLX(1) insns. */
+ /* B simply branches so we do nothing here. */
+ /* Note: BLX(1) doesnt fall here but instead it falls into
+ extension space. */
+ if (bit (arm_insn_r->arm_insn, 24))
+ {
+ record_buf[0] = ARM_LR_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
+
+ return 0;
+}
+
+/* Handling opcode 110 insns. */
+
+static int
+arm_record_unsupported_insn (insn_decode_record *arm_insn_r)
+{
+ 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;
+}
+
+/* Record handler for vector data transfer instructions. */
+
+static int
+arm_record_vdata_transfer_insn (insn_decode_record *arm_insn_r)
+{
+ 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);
+ bit_l = bit (arm_insn_r->arm_insn, 20);
+ bit_c = bit (arm_insn_r->arm_insn, 8);
+
+ /* Handle VMOV instruction. */
+ if (bit_l && bit_c)
+ {
+ record_buf[0] = reg_t;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (bit_l && !bit_c)
+ {
+ /* 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));
+
+ arm_insn_r->reg_rec_count = 1;
+ }
+ /* Handle VMRS instruction. */
+ else if (bits_a == 0x07)
+ {
+ if (reg_t == 15)
+ reg_t = ARM_PS_REGNUM;
+
+ record_buf[0] = reg_t;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ else if (!bit_l && !bit_c)
+ {
+ /* 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));
+
+ arm_insn_r->reg_rec_count = 1;
+ }
+ /* Handle VMSR instruction. */
+ else if (bits_a == 0x07)
+ {
+ record_buf[0] = ARM_FPSCR_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ else if (!bit_l && bit_c)
+ {
+ /* Handle VMOV instruction. */
+ if (!(bits_a & 0x04))
+ {
+ record_buf[0] = (reg_v | (bit (arm_insn_r->arm_insn, 7) << 4))
+ + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ /* Handle VDUP instruction. */
+ else
+ {
+ if (bit (arm_insn_r->arm_insn, 21))
+ {
+ reg_v = reg_v | (bit (arm_insn_r->arm_insn, 7) << 4);
+ record_buf[0] = reg_v + ARM_D0_REGNUM;
+ record_buf[1] = reg_v + ARM_D0_REGNUM + 1;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else
+ {
+ reg_v = reg_v | (bit (arm_insn_r->arm_insn, 7) << 4);
+ record_buf[0] = reg_v + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ }
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
+ return 0;
+}
+
+/* Record handler for extension register load/store instructions. */
+
+static int
+arm_record_exreg_ld_st_insn (insn_decode_record *arm_insn_r)
+{
+ uint32_t opcode, single_reg;
+ uint8_t op_vldm_vstm;
+ uint32_t record_buf[8], record_buf_mem[128];
+ 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);
+ op_vldm_vstm = opcode & 0x1b;
+
+ /* Handle VMOV instructions. */
+ if ((opcode & 0x1e) == 0x04)
+ {
+ if (bit (arm_insn_r->arm_insn, 4))
+ {
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else
+ {
+ uint8_t reg_m = (bits (arm_insn_r->arm_insn, 0, 3) << 1)
+ | bit (arm_insn_r->arm_insn, 5);
+
+ 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;
+ }
+ else
+ {
+ record_buf[0] = reg_m + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ }
+ /* Handle VSTM and VPUSH instructions. */
+ else if (op_vldm_vstm == 0x08 || op_vldm_vstm == 0x0a
+ || op_vldm_vstm == 0x12)
+ {
+ uint32_t start_address, reg_rn, imm_off32, imm_off8, memory_count;
+ uint32_t memory_index = 0;
+
+ 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;
+ memory_count = imm_off8;
+
+ if (bit (arm_insn_r->arm_insn, 23))
+ start_address = u_regval;
+ else
+ start_address = u_regval - imm_off32;
+
+ if (bit (arm_insn_r->arm_insn, 21))
+ {
+ record_buf[0] = reg_rn;
+ arm_insn_r->reg_rec_count = 1;
+ }
+
+ while (memory_count > 0)
+ {
+ if (!single_reg)
+ {
+ record_buf_mem[memory_index] = start_address;
+ record_buf_mem[memory_index + 1] = 4;
+ 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;
+ start_address = start_address + 8;
+ memory_index = memory_index + 4;
+ }
+ memory_count--;
+ }
+ arm_insn_r->mem_rec_count = (memory_index >> 1);
+ }
+ /* Handle VLDM instructions. */
+ else if (op_vldm_vstm == 0x09 || op_vldm_vstm == 0x0b
+ || op_vldm_vstm == 0x13)
+ {
+ uint32_t reg_count, reg_vd;
+ uint32_t reg_index = 0;
+
+ 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);
+
+ if (bit (arm_insn_r->arm_insn, 21))
+ record_buf[reg_index++] = bits (arm_insn_r->arm_insn, 16, 19);
+
+ while (reg_count > 0)
+ {
+ 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;
+
+ reg_count--;
+ }
+ arm_insn_r->reg_rec_count = reg_index;
+ }
+ /* VSTR Vector store register. */
+ else if ((opcode & 0x13) == 0x10)
+ {
+ uint32_t start_address, reg_rn, imm_off32, imm_off8, memory_count;
+ uint32_t memory_index = 0;
+
+ 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;
+ memory_count = imm_off8;
+
+ if (bit (arm_insn_r->arm_insn, 23))
+ start_address = u_regval + imm_off32;
+ else
+ start_address = u_regval - imm_off32;
+
+ if (single_reg)
+ {
+ record_buf_mem[memory_index] = start_address;
+ record_buf_mem[memory_index + 1] = 4;
+ 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;
+ arm_insn_r->mem_rec_count = 2;
+ }
+ }
+ /* VLDR Vector load register. */
+ else if ((opcode & 0x13) == 0x11)
+ {
+ uint32_t reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
+
+ if (!single_reg)
+ {
+ reg_vd = reg_vd | (bit (arm_insn_r->arm_insn, 22) << 4);
+ record_buf[0] = ARM_D0_REGNUM + reg_vd;
+ }
+ else
+ {
+ reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
+ record_buf[0] = num_regs + reg_vd;
+ }
+ arm_insn_r->reg_rec_count = 1;
+ }
+
+ 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);
+ return 0;
+}
+
+/* Record handler for arm/thumb mode VFP data processing instructions. */
+
+static int
+arm_record_vfp_data_proc_insn (insn_decode_record *arm_insn_r)
+{
+ uint32_t opc1, opc2, opc3, dp_op_sz, bit_d, reg_vd;
+ uint32_t record_buf[4];
+ enum insn_types {INSN_T0, INSN_T1, INSN_T2, INSN_T3, INSN_INV};
+ enum insn_types curr_insn_type = INSN_INV;
+
+ reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
+ opc1 = bits (arm_insn_r->arm_insn, 20, 23);
+ opc2 = bits (arm_insn_r->arm_insn, 16, 19);
+ opc3 = bits (arm_insn_r->arm_insn, 6, 7);
+ dp_op_sz = bit (arm_insn_r->arm_insn, 8);
+ bit_d = bit (arm_insn_r->arm_insn, 22);
+ opc1 = opc1 & 0x04;
+
+ /* Handle VMLA, VMLS. */
+ if (opc1 == 0x00)
+ {
+ if (bit (arm_insn_r->arm_insn, 10))
+ {
+ if (bit (arm_insn_r->arm_insn, 6))
+ curr_insn_type = INSN_T0;
+ else
+ curr_insn_type = INSN_T1;
+ }
+ else
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ }
+ /* Handle VNMLA, VNMLS, VNMUL. */
+ else if (opc1 == 0x01)
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ /* Handle VMUL. */
+ else if (opc1 == 0x02 && !(opc3 & 0x01))
+ {
+ if (bit (arm_insn_r->arm_insn, 10))
+ {
+ if (bit (arm_insn_r->arm_insn, 6))
+ curr_insn_type = INSN_T0;
+ else
+ curr_insn_type = INSN_T1;
+ }
+ else
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ }
+ /* Handle VADD, VSUB. */
+ else if (opc1 == 0x03)
+ {
+ if (!bit (arm_insn_r->arm_insn, 9))
+ {
+ if (bit (arm_insn_r->arm_insn, 6))
+ curr_insn_type = INSN_T0;
+ else
+ curr_insn_type = INSN_T1;
+ }
+ else
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ }
+ /* Handle VDIV. */
+ else if (opc1 == 0x0b)
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ /* Handle all other vfp data processing instructions. */
+ else if (opc1 == 0x0b)
+ {
+ /* Handle VMOV. */
+ if (!(opc3 & 0x01) || (opc2 == 0x00 && opc3 == 0x01))
+ {
+ if (bit (arm_insn_r->arm_insn, 4))
+ {
+ if (bit (arm_insn_r->arm_insn, 6))
+ curr_insn_type = INSN_T0;
+ else
+ curr_insn_type = INSN_T1;
+ }
+ else
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ }
+ /* Handle VNEG and VABS. */
+ else if ((opc2 == 0x01 && opc3 == 0x01)
+ || (opc2 == 0x00 && opc3 == 0x03))
+ {
+ if (!bit (arm_insn_r->arm_insn, 11))
+ {
+ if (bit (arm_insn_r->arm_insn, 6))
+ curr_insn_type = INSN_T0;
+ else
+ curr_insn_type = INSN_T1;
+ }
+ else
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ }
+ /* Handle VSQRT. */
+ else if (opc2 == 0x01 && opc3 == 0x03)
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ /* Handle VCVT. */
+ else if (opc2 == 0x07 && opc3 == 0x03)
+ {
+ if (!dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ else if (opc3 & 0x01)
+ {
+ /* Handle VCVT. */
+ if ((opc2 == 0x08) || (opc2 & 0x0e) == 0x0c)
+ {
+ if (!bit (arm_insn_r->arm_insn, 18))
+ curr_insn_type = INSN_T2;
+ else
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ }
+ /* Handle VCVT. */
+ else if ((opc2 & 0x0e) == 0x0a || (opc2 & 0x0e) == 0x0e)
+ {
+ if (dp_op_sz)
+ curr_insn_type = INSN_T1;
+ else
+ curr_insn_type = INSN_T2;
+ }
+ /* Handle VCVTB, VCVTT. */
+ else if ((opc2 & 0x0e) == 0x02)
+ curr_insn_type = INSN_T2;
+ /* Handle VCMP, VCMPE. */
+ else if ((opc2 & 0x0e) == 0x04)
+ curr_insn_type = INSN_T3;
+ }
+ }
+
+ switch (curr_insn_type)
+ {
+ case INSN_T0:
+ reg_vd = reg_vd | (bit_d << 4);
+ record_buf[0] = reg_vd + ARM_D0_REGNUM;
+ record_buf[1] = reg_vd + ARM_D0_REGNUM + 1;
+ arm_insn_r->reg_rec_count = 2;
+ break;
+
+ case INSN_T1:
+ reg_vd = reg_vd | (bit_d << 4);
+ record_buf[0] = reg_vd + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ break;
+
+ case INSN_T2:
+ reg_vd = (reg_vd << 1) | bit_d;
+ record_buf[0] = reg_vd + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ break;
+
+ case INSN_T3:
+ record_buf[0] = ARM_FPSCR_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ break;
+
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
+ return 0;
+}
+
+/* Handling opcode 110 insns. */
+
+static int
+arm_record_asimd_vfp_coproc (insn_decode_record *arm_insn_r)
+{
+ uint32_t op, op1, op1_sbit, op1_ebit, coproc;
+
+ coproc = bits (arm_insn_r->arm_insn, 8, 11);
+ op1 = bits (arm_insn_r->arm_insn, 20, 25);
+ op1_ebit = bit (arm_insn_r->arm_insn, 20);
+
+ if ((coproc & 0x0e) == 0x0a)
+ {
+ /* Handle extension register ld/st instructions. */
+ if (!(op1 & 0x20))
+ return arm_record_exreg_ld_st_insn (arm_insn_r);
+
+ /* 64-bit transfers between arm core and extension registers. */
+ if ((op1 & 0x3e) == 0x04)
+ return arm_record_exreg_ld_st_insn (arm_insn_r);
+ }
+ else
+ {
+ /* Handle coprocessor ld/st instructions. */
+ if (!(op1 & 0x3a))
+ {
+ /* Store. */
+ if (!op1_ebit)
+ return arm_record_unsupported_insn (arm_insn_r);
+ else
+ /* Load. */
+ return arm_record_unsupported_insn (arm_insn_r);
+ }
+
+ /* Move to coprocessor from two arm core registers. */
+ if (op1 == 0x4)
+ return arm_record_unsupported_insn (arm_insn_r);
+
+ /* Move to two arm core registers from coprocessor. */
+ if (op1 == 0x5)
+ {
+ uint32_t reg_t[2];
+
+ reg_t[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ reg_t[1] = bits (arm_insn_r->arm_insn, 16, 19);
+ arm_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, reg_t);
+ return 0;
+ }
+ }
+ return arm_record_unsupported_insn (arm_insn_r);
+}
+
+/* Handling opcode 111 insns. */
+
+static int
+arm_record_coproc_data_proc (insn_decode_record *arm_insn_r)
+{
+ uint32_t op, op1_sbit, op1_ebit, coproc;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (arm_insn_r->gdbarch);
+ struct regcache *reg_cache = arm_insn_r->regcache;
+ ULONGEST u_regval = 0;
+
+ arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 24, 27);
+ coproc = bits (arm_insn_r->arm_insn, 8, 11);
+ op1_sbit = bit (arm_insn_r->arm_insn, 24);
+ op1_ebit = bit (arm_insn_r->arm_insn, 20);
+ op = bit (arm_insn_r->arm_insn, 4);
+
+ /* Handle arm SWI/SVC system call instructions. */
+ if (op1_sbit)
+ {
+ if (tdep->arm_syscall_record != NULL)
+ {
+ ULONGEST svc_operand, svc_number;
+
+ svc_operand = (0x00ffffff & arm_insn_r->arm_insn);
+
+ if (svc_operand) /* OABI. */
+ svc_number = svc_operand - 0x900000;
+ else /* EABI. */
+ regcache_raw_read_unsigned (reg_cache, 7, &svc_number);
+
+ return tdep->arm_syscall_record (reg_cache, svc_number);
+ }
+ else
+ {
+ printf_unfiltered (_("no syscall record support\n"));
+ return -1;
+ }
+ }
+
+ if ((coproc & 0x0e) == 0x0a)
+ {
+ /* VFP data-processing instructions. */
+ if (!op1_sbit && !op)
+ return arm_record_vfp_data_proc_insn (arm_insn_r);
+
+ /* Advanced SIMD, VFP instructions. */
+ if (!op1_sbit && op)
+ return arm_record_vdata_transfer_insn (arm_insn_r);
+ }
+ else
+ {
+ /* Coprocessor data operations. */
+ if (!op1_sbit && !op)
+ return arm_record_unsupported_insn (arm_insn_r);
+
+ /* Move to Coprocessor from ARM core register. */
+ if (!op1_sbit && !op1_ebit && op)
+ return arm_record_unsupported_insn (arm_insn_r);
+
+ /* Move to arm core register from coprocessor. */
+ if (!op1_sbit && op1_ebit && op)
+ {
+ uint32_t record_buf[1];
+
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ if (record_buf[0] == 15)
+ record_buf[0] = ARM_PS_REGNUM;
+
+ arm_insn_r->reg_rec_count = 1;
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count,
+ record_buf);
+ return 0;
+ }
+ }
+
+ return arm_record_unsupported_insn (arm_insn_r);
+}
+
+/* Handling opcode 000 insns. */
+
+static int
+thumb_record_shift_add_sub (insn_decode_record *thumb_insn_r)
+{
+ uint32_t record_buf[8];
+ uint32_t reg_src1 = 0;
+
+ reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
+
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = reg_src1;
+ thumb_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+
+ return 0;
+}
+
+
+/* Handling opcode 001 insns. */
+
+static int
+thumb_record_add_sub_cmp_mov (insn_decode_record *thumb_insn_r)
+{
+ uint32_t record_buf[8];
+ uint32_t reg_src1 = 0;
+
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = reg_src1;
+ thumb_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+
+ return 0;
+}
+
+/* Handling opcode 010 insns. */
+
+static int
+thumb_record_ld_st_reg_offset (insn_decode_record *thumb_insn_r)
+{
+ struct regcache *reg_cache = thumb_insn_r->regcache;
+ uint32_t record_buf[8], record_buf_mem[8];
+
+ uint32_t reg_src1 = 0, reg_src2 = 0;
+ uint32_t opcode1 = 0, opcode2 = 0, opcode3 = 0;
+
+ ULONGEST u_regval[2] = {0};
+
+ opcode1 = bits (thumb_insn_r->arm_insn, 10, 12);
+
+ if (bit (thumb_insn_r->arm_insn, 12))
+ {
+ /* Handle load/store register offset. */
+ opcode2 = bits (thumb_insn_r->arm_insn, 9, 10);
+ if (opcode2 >= 12 && opcode2 <= 15)
+ {
+ /* LDR(2), LDRB(2) , LDRH(2), LDRSB, LDRSH. */
+ reg_src1 = bits (thumb_insn_r->arm_insn,0, 2);
+ record_buf[0] = reg_src1;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (opcode2 >= 8 && opcode2 <= 10)
+ {
+ /* STR(2), STRB(2), STRH(2) . */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
+ reg_src2 = bits (thumb_insn_r->arm_insn, 6, 8);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
+ if (8 == opcode2)
+ record_buf_mem[0] = 4; /* STR (2). */
+ else if (10 == opcode2)
+ record_buf_mem[0] = 1; /* STRB (2). */
+ else if (9 == opcode2)
+ record_buf_mem[0] = 2; /* STRH (2). */
+ record_buf_mem[1] = u_regval[0] + u_regval[1];
+ thumb_insn_r->mem_rec_count = 1;
+ }
+ }
+ else if (bit (thumb_insn_r->arm_insn, 11))
+ {
+ /* Handle load from literal pool. */
+ /* LDR(3). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ record_buf[0] = reg_src1;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (opcode1)
+ {
+ opcode2 = bits (thumb_insn_r->arm_insn, 8, 9);
+ opcode3 = bits (thumb_insn_r->arm_insn, 0, 2);
+ if ((3 == opcode2) && (!opcode3))
+ {
+ /* Branch with exchange. */
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb_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;
+ thumb_insn_r->reg_rec_count = 2;
+ }
+ }
+ else
+ {
+ /* Format 5; data processing insns. */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
+ if (bit (thumb_insn_r->arm_insn, 7))
+ {
+ reg_src1 = reg_src1 + 8;
+ }
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = reg_src1;
+ thumb_insn_r->reg_rec_count = 2;
+ }
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+ MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
+ record_buf_mem);
+
+ return 0;
+}
+
+/* Handling opcode 001 insns. */
+
+static int
+thumb_record_ld_st_imm_offset (insn_decode_record *thumb_insn_r)
+{
+ struct regcache *reg_cache = thumb_insn_r->regcache;
+ uint32_t record_buf[8], record_buf_mem[8];
+
+ uint32_t reg_src1 = 0;
+ uint32_t opcode = 0, immed_5 = 0;
+
+ ULONGEST u_regval = 0;
+
+ opcode = bits (thumb_insn_r->arm_insn, 11, 12);
+
+ if (opcode)
+ {
+ /* LDR(1). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
+ record_buf[0] = reg_src1;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ /* STR(1). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
+ immed_5 = bits (thumb_insn_r->arm_insn, 6, 10);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = u_regval + (immed_5 * 4);
+ thumb_insn_r->mem_rec_count = 1;
+ }
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+ MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
+ record_buf_mem);
+
+ return 0;
+}
+
+/* Handling opcode 100 insns. */
+
+static int
+thumb_record_ld_st_stack (insn_decode_record *thumb_insn_r)
+{
+ struct regcache *reg_cache = thumb_insn_r->regcache;
+ uint32_t record_buf[8], record_buf_mem[8];
+
+ uint32_t reg_src1 = 0;
+ uint32_t opcode = 0, immed_8 = 0, immed_5 = 0;
+
+ ULONGEST u_regval = 0;
+
+ opcode = bits (thumb_insn_r->arm_insn, 11, 12);
+
+ if (3 == opcode)
+ {
+ /* LDR(4). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ record_buf[0] = reg_src1;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == opcode)
+ {
+ /* LDRH(1). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
+ record_buf[0] = reg_src1;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (2 == opcode)
+ {
+ /* STR(3). */
+ immed_8 = bits (thumb_insn_r->arm_insn, 0, 7);
+ regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = u_regval + (immed_8 * 4);
+ thumb_insn_r->mem_rec_count = 1;
+ }
+ else if (0 == opcode)
+ {
+ /* STRH(1). */
+ immed_5 = bits (thumb_insn_r->arm_insn, 6, 10);
+ reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
+ record_buf_mem[0] = 2;
+ record_buf_mem[1] = u_regval + (immed_5 * 2);
+ thumb_insn_r->mem_rec_count = 1;
+ }
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+ MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
+ record_buf_mem);
+
+ return 0;
+}
+
+/* Handling opcode 101 insns. */
+
+static int
+thumb_record_misc (insn_decode_record *thumb_insn_r)
+{
+ struct regcache *reg_cache = thumb_insn_r->regcache;
+
+ uint32_t opcode = 0, opcode1 = 0, opcode2 = 0;
+ uint32_t register_bits = 0, register_count = 0;
+ uint32_t register_list[8] = {0}, index = 0, start_address = 0;
+ uint32_t record_buf[24], record_buf_mem[48];
+ uint32_t reg_src1;
+
+ ULONGEST u_regval = 0;
+
+ opcode = bits (thumb_insn_r->arm_insn, 11, 12);
+ opcode1 = bits (thumb_insn_r->arm_insn, 8, 12);
+ opcode2 = bits (thumb_insn_r->arm_insn, 9, 12);
+
+ if (14 == opcode2)
+ {
+ /* POP. */
+ register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ record_buf[index++] = register_count;
+ register_bits = register_bits >> 1;
+ register_count++;
+ }
+ record_buf[index++] = ARM_PS_REGNUM;
+ record_buf[index++] = ARM_SP_REGNUM;
+ thumb_insn_r->reg_rec_count = index;
+ }
+ else if (10 == opcode2)
+ {
+ /* PUSH. */
+ register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
+ regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
+ start_address = u_regval - \
+ (4 * (bit (thumb_insn_r->arm_insn, 8) + register_count));
+ thumb_insn_r->mem_rec_count = register_count;
+ while (register_count)
+ {
+ record_buf_mem[(register_count * 2) - 1] = start_address;
+ record_buf_mem[(register_count * 2) - 2] = 4;
+ start_address = start_address + 4;
+ register_count--;
+ }
+ record_buf[0] = ARM_SP_REGNUM;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (0x1E == opcode1)
+ {
+ /* BKPT insn. */
+ /* Handle enhanced software breakpoint insn, BKPT. */
+ /* CPSR is changed to be executed in ARM state, disabling normal
+ interrupts, entering abort mode. */
+ /* According to high vector configuration PC is set. */
+ /* User hits breakpoint and type reverse, in that case, we need to go back with
+ previous CPSR and Program Counter. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ thumb_insn_r->reg_rec_count = 2;
+ /* We need to save SPSR value, which is not yet done. */
+ printf_unfiltered (_("Process record does not support instruction "
+ "0x%0x at address %s.\n"),
+ thumb_insn_r->arm_insn,
+ paddress (thumb_insn_r->gdbarch,
+ thumb_insn_r->this_addr));
+ return -1;
+ }
+ else if ((0 == opcode) || (1 == opcode))
+ {
+ /* ADD(5), ADD(6). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ record_buf[0] = reg_src1;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (2 == opcode)
+ {
+ /* ADD(7), SUB(4). */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ record_buf[0] = ARM_SP_REGNUM;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+ MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
+ record_buf_mem);
+
+ return 0;
+}
+
+/* Handling opcode 110 insns. */
+
+static int
+thumb_record_ldm_stm_swi (insn_decode_record *thumb_insn_r)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (thumb_insn_r->gdbarch);
+ struct regcache *reg_cache = thumb_insn_r->regcache;
+
+ uint32_t ret = 0; /* function return value: -1:record failure ; 0:success */
+ uint32_t reg_src1 = 0;
+ uint32_t opcode1 = 0, opcode2 = 0, register_bits = 0, register_count = 0;
+ uint32_t register_list[8] = {0}, index = 0, start_address = 0;
+ uint32_t record_buf[24], record_buf_mem[48];
+
+ ULONGEST u_regval = 0;
+
+ opcode1 = bits (thumb_insn_r->arm_insn, 8, 12);
+ opcode2 = bits (thumb_insn_r->arm_insn, 11, 12);
+
+ if (1 == opcode2)
+ {
+
+ /* LDMIA. */
+ register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
+ /* Get Rn. */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ record_buf[index++] = register_count;
+ register_bits = register_bits >> 1;
+ register_count++;
+ }
+ record_buf[index++] = reg_src1;
+ thumb_insn_r->reg_rec_count = index;
+ }
+ else if (0 == opcode2)
+ {
+ /* It handles both STMIA. */
+ register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
+ /* Get Rn. */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
+ start_address = u_regval;
+ thumb_insn_r->mem_rec_count = register_count;
+ while (register_count)
+ {
+ record_buf_mem[(register_count * 2) - 1] = start_address;
+ record_buf_mem[(register_count * 2) - 2] = 4;
+ start_address = start_address + 4;
+ register_count--;
+ }
+ }
+ else if (0x1F == opcode1)
+ {
+ /* Handle arm syscall insn. */
+ if (tdep->arm_syscall_record != NULL)
+ {
+ regcache_raw_read_unsigned (reg_cache, 7, &u_regval);
+ ret = tdep->arm_syscall_record (reg_cache, u_regval);
+ }
+ else
+ {
+ printf_unfiltered (_("no syscall record support\n"));
+ return -1;
+ }
+ }
+
+ /* B (1), conditional branch is automatically taken care in process_record,
+ as PC is saved there. */
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+ MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
+ record_buf_mem);
+
+ return ret;
+}
+
+/* Handling opcode 111 insns. */
+
+static int
+thumb_record_branch (insn_decode_record *thumb_insn_r)
+{
+ uint32_t record_buf[8];
+ uint32_t bits_h = 0;
+
+ bits_h = bits (thumb_insn_r->arm_insn, 11, 12);
+
+ if (2 == bits_h || 3 == bits_h)
+ {
+ /* BL */
+ record_buf[0] = ARM_LR_REGNUM;
+ thumb_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == bits_h)
+ {
+ /* BLX(1). */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ thumb_insn_r->reg_rec_count = 2;
+ }
+
+ /* B(2) is automatically taken care in process_record, as PC is
+ saved there. */
+
+ REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
+
+ return 0;
+}
+
+/* Handler for thumb2 load/store multiple instructions. */
+
+static int
+thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+ uint32_t reg_rn, op;
+ uint32_t register_bits = 0, register_count = 0;
+ uint32_t index = 0, start_address = 0;
+ uint32_t record_buf[24], record_buf_mem[48];
+
+ ULONGEST u_regval = 0;
+
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+ op = bits (thumb2_insn_r->arm_insn, 23, 24);
+
+ if (0 == op || 3 == op)
+ {
+ if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* Handle RFE instruction. */
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ /* Handle SRS instruction after reading banked SP. */
+ return arm_record_unsupported_insn (thumb2_insn_r);
+ }
+ }
+ else if (1 == op || 2 == op)
+ {
+ if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions. */
+ register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ record_buf[index++] = register_count;
+
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
+ record_buf[index++] = reg_rn;
+ record_buf[index++] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = index;
+ }
+ else
+ {
+ /* Handle STM/STMIA/STMEA and STMDB/STMFD. */
+ register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ register_count++;
+
+ register_bits = register_bits >> 1;
+ }
+
+ if (1 == op)
+ {
+ /* Start address calculation for LDMDB/LDMEA. */
+ start_address = u_regval;
+ }
+ else if (2 == op)
+ {
+ /* Start address calculation for LDMDB/LDMEA. */
+ start_address = u_regval - register_count * 4;
+ }
+
+ thumb2_insn_r->mem_rec_count = register_count;
+ while (register_count)
+ {
+ record_buf_mem[register_count * 2 - 1] = start_address;
+ record_buf_mem[register_count * 2 - 2] = 4;
+ start_address = start_address + 4;
+ register_count--;
+ }
+ record_buf[0] = reg_rn;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+ }
+
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Handler for thumb2 load/store (dual/exclusive) and table branch
+ instructions. */
+
+static int
+thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+ uint32_t reg_rd, reg_rn, offset_imm;
+ uint32_t reg_dest1, reg_dest2;
+ uint32_t address, offset_addr;
+ uint32_t record_buf[8], record_buf_mem[8];
+ uint32_t op1, op2, op3;
+ LONGEST s_word;
+
+ ULONGEST u_regval[2];
+
+ op1 = bits (thumb2_insn_r->arm_insn, 23, 24);
+ op2 = bits (thumb2_insn_r->arm_insn, 20, 21);
+ op3 = bits (thumb2_insn_r->arm_insn, 4, 7);
+
+ if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
+ {
+ if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3)))
+ {
+ reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[0] = reg_dest1;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3))
+ {
+ reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11);
+ record_buf[2] = reg_dest2;
+ thumb2_insn_r->reg_rec_count = 3;
+ }
+ }
+ else
+ {
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
+
+ if (0 == op1 && 0 == op2)
+ {
+ /* Handle STREX. */
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+ address = u_regval[0] + (offset_imm * 4);
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = address;
+ thumb2_insn_r->mem_rec_count = 1;
+ reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
+ record_buf[0] = reg_rd;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else if (1 == op1 && 0 == op2)
+ {
+ reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
+ record_buf[0] = reg_rd;
+ thumb2_insn_r->reg_rec_count = 1;
+ address = u_regval[0];
+ record_buf_mem[1] = address;
+
+ if (4 == op3)
+ {
+ /* Handle STREXB. */
+ record_buf_mem[0] = 1;
+ thumb2_insn_r->mem_rec_count = 1;
+ }
+ else if (5 == op3)
+ {
+ /* Handle STREXH. */
+ record_buf_mem[0] = 2 ;
+ thumb2_insn_r->mem_rec_count = 1;
+ }
+ else if (7 == op3)
+ {
+ /* Handle STREXD. */
+ address = u_regval[0];
+ record_buf_mem[0] = 4;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = address + 4;
+ thumb2_insn_r->mem_rec_count = 2;
+ }
+ }
+ else
+ {
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+
+ if (bit (thumb2_insn_r->arm_insn, 24))
+ {
+ if (bit (thumb2_insn_r->arm_insn, 23))
+ offset_addr = u_regval[0] + (offset_imm * 4);
+ else
+ offset_addr = u_regval[0] - (offset_imm * 4);
+
+ address = offset_addr;
+ }
+ else
+ address = u_regval[0];
+
+ record_buf_mem[0] = 4;
+ record_buf_mem[1] = address;
+ record_buf_mem[2] = 4;
+ record_buf_mem[3] = address + 4;
+ thumb2_insn_r->mem_rec_count = 2;
+ record_buf[0] = reg_rn;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Handler for thumb2 data processing (shift register and modified immediate)
+ instructions. */
+
+static int
+thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t reg_rd, op;
+ uint32_t record_buf[8];
+
+ op = bits (thumb2_insn_r->arm_insn, 21, 24);
+ reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
+ {
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ record_buf[0] = reg_rd;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Generic handler for thumb2 instructions which effect destination and PS
+ registers. */
+
+static int
+thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t reg_rd;
+ uint32_t record_buf[8];
+
+ reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ record_buf[0] = reg_rd;
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Handler for thumb2 branch and miscellaneous control instructions. */
+
+static int
+thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t op, op1, op2;
+ uint32_t record_buf[8];
+
+ op = bits (thumb2_insn_r->arm_insn, 20, 26);
+ op1 = bits (thumb2_insn_r->arm_insn, 12, 14);
+ op2 = bits (thumb2_insn_r->arm_insn, 8, 11);
+
+ /* Handle MSR insn. */
+ if (!(op1 & 0x2) && 0x38 == op)
+ {
+ if (!(op2 & 0x3))
+ {
+ /* CPSR is going to be changed. */
+ record_buf[0] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 1;
+ }
+ else
+ {
+ arm_record_unsupported_insn(thumb2_insn_r);
+ return -1;
+ }
+ }
+ else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5))
+ {
+ /* BLX. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Handler for thumb2 store single data item instructions. */
+
+static int
+thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+
+ uint32_t reg_rn, reg_rm, offset_imm, shift_imm;
+ uint32_t address, offset_addr;
+ uint32_t record_buf[8], record_buf_mem[8];
+ uint32_t op1, op2;
+
+ ULONGEST u_regval[2];
+
+ op1 = bits (thumb2_insn_r->arm_insn, 21, 23);
+ op2 = bits (thumb2_insn_r->arm_insn, 6, 11);
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
+
+ if (bit (thumb2_insn_r->arm_insn, 23))
+ {
+ /* T2 encoding. */
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11);
+ offset_addr = u_regval[0] + offset_imm;
+ address = offset_addr;
+ }
+ else
+ {
+ /* T3 encoding. */
+ if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20))
+ {
+ /* Handle STRB (register). */
+ reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3);
+ regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]);
+ shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5);
+ offset_addr = u_regval[1] << shift_imm;
+ address = u_regval[0] + offset_addr;
+ }
+ else
+ {
+ offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
+ if (bit (thumb2_insn_r->arm_insn, 10))
+ {
+ if (bit (thumb2_insn_r->arm_insn, 9))
+ offset_addr = u_regval[0] + offset_imm;
+ else
+ offset_addr = u_regval[0] - offset_imm;
+
+ address = offset_addr;
+ }
+ else
+ address = u_regval[0];
+ }
+ }
+
+ switch (op1)
+ {
+ /* Store byte instructions. */
+ case 4:
+ case 0:
+ record_buf_mem[0] = 1;
+ break;
+ /* Store half word instructions. */
+ case 1:
+ case 5:
+ record_buf_mem[0] = 2;
+ break;
+ /* Store word instructions. */
+ case 2:
+ case 6:
+ record_buf_mem[0] = 4;
+ break;
+
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
+
+ record_buf_mem[1] = address;
+ thumb2_insn_r->mem_rec_count = 1;
+ record_buf[0] = reg_rn;
+ thumb2_insn_r->reg_rec_count = 1;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Handler for thumb2 load memory hints instructions. */
+
+static int
+thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t record_buf[8];
+ uint32_t reg_rt, reg_rn;
+
+ reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+
+ if (ARM_PC_REGNUM != reg_rt)
+ {
+ record_buf[0] = reg_rt;
+ record_buf[1] = reg_rn;
+ record_buf[2] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 3;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+ }
+
+ return ARM_RECORD_FAILURE;
+}
+
+/* Handler for thumb2 load word instructions. */
+
+static int
+thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t opcode1 = 0, opcode2 = 0;
+ uint32_t record_buf[8];
+
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[1] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 2;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Handler for thumb2 long multiply, long multiply accumulate, and
+ divide instructions. */
+
+static int
+thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t opcode1 = 0, opcode2 = 0;
+ uint32_t record_buf[8];
+ uint32_t reg_src1 = 0;
+
+ opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
+ opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
+
+ if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6))
+ {
+ /* Handle SMULL, UMULL, SMULAL. */
+ /* Handle SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
+ record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[2] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 3;
+ }
+ else if (1 == opcode1 || 3 == opcode2)
+ {
+ /* Handle SDIV and UDIV. */
+ record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
+ record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
+ record_buf[2] = ARM_PS_REGNUM;
+ thumb2_insn_r->reg_rec_count = 3;
+ }
+ else
+ return ARM_RECORD_FAILURE;
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ return ARM_RECORD_SUCCESS;
+}
+
+/* Record handler for thumb32 coprocessor instructions. */
+
+static int
+thumb2_record_coproc_insn (insn_decode_record *thumb2_insn_r)
+{
+ if (bit (thumb2_insn_r->arm_insn, 25))
+ return arm_record_coproc_data_proc (thumb2_insn_r);
+ else
+ return arm_record_asimd_vfp_coproc (thumb2_insn_r);
+}
+
+/* Record handler for advance SIMD structure load/store instructions. */
+
+static int
+thumb2_record_asimd_struct_ld_st (insn_decode_record *thumb2_insn_r)
+{
+ struct regcache *reg_cache = thumb2_insn_r->regcache;
+ uint32_t l_bit, a_bit, b_bits;
+ uint32_t record_buf[128], record_buf_mem[128];
+ uint32_t reg_rn, reg_vd, address, f_esize, f_elem;
+ uint32_t index_r = 0, index_e = 0, bf_regs = 0, index_m = 0, loop_t = 0;
+ uint8_t f_ebytes;
+
+ l_bit = bit (thumb2_insn_r->arm_insn, 21);
+ a_bit = bit (thumb2_insn_r->arm_insn, 23);
+ b_bits = bits (thumb2_insn_r->arm_insn, 8, 11);
+ reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
+ reg_vd = bits (thumb2_insn_r->arm_insn, 12, 15);
+ reg_vd = (bit (thumb2_insn_r->arm_insn, 22) << 4) | reg_vd;
+ f_ebytes = (1 << bits (thumb2_insn_r->arm_insn, 6, 7));
+ f_esize = 8 * f_ebytes;
+ f_elem = 8 / f_ebytes;
+
+ if (!l_bit)
+ {
+ ULONGEST u_regval = 0;
+ regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
+ address = u_regval;
+
+ if (!a_bit)
+ {
+ /* Handle VST1. */
+ if (b_bits == 0x02 || b_bits == 0x0a || (b_bits & 0x0e) == 0x06)
+ {
+ if (b_bits == 0x07)
+ bf_regs = 1;
+ else if (b_bits == 0x0a)
+ bf_regs = 2;
+ else if (b_bits == 0x06)
+ bf_regs = 3;
+ else if (b_bits == 0x02)
+ bf_regs = 4;
+ else
+ bf_regs = 0;
+
+ for (index_r = 0; index_r < bf_regs; index_r++)
+ {
+ for (index_e = 0; index_e < f_elem; index_e++)
+ {
+ record_buf_mem[index_m++] = f_ebytes;
+ record_buf_mem[index_m++] = address;
+ address = address + f_ebytes;
+ thumb2_insn_r->mem_rec_count += 1;
+ }
+ }
+ }
+ /* Handle VST2. */
+ else if (b_bits == 0x03 || (b_bits & 0x0e) == 0x08)
+ {
+ if (b_bits == 0x09 || b_bits == 0x08)
+ bf_regs = 1;
+ else if (b_bits == 0x03)
+ bf_regs = 2;
+ else
+ bf_regs = 0;
+
+ for (index_r = 0; index_r < bf_regs; index_r++)
+ for (index_e = 0; index_e < f_elem; index_e++)
+ {
+ for (loop_t = 0; loop_t < 2; loop_t++)
+ {
+ record_buf_mem[index_m++] = f_ebytes;
+ record_buf_mem[index_m++] = address + (loop_t * f_ebytes);
+ thumb2_insn_r->mem_rec_count += 1;
+ }
+ address = address + (2 * f_ebytes);
+ }
+ }
+ /* Handle VST3. */
+ else if ((b_bits & 0x0e) == 0x04)
+ {
+ for (index_e = 0; index_e < f_elem; index_e++)
+ {
+ for (loop_t = 0; loop_t < 3; loop_t++)
+ {
+ record_buf_mem[index_m++] = f_ebytes;
+ record_buf_mem[index_m++] = address + (loop_t * f_ebytes);
+ thumb2_insn_r->mem_rec_count += 1;
+ }
+ address = address + (3 * f_ebytes);
+ }
+ }
+ /* Handle VST4. */
+ else if (!(b_bits & 0x0e))
+ {
+ for (index_e = 0; index_e < f_elem; index_e++)
+ {
+ for (loop_t = 0; loop_t < 4; loop_t++)
+ {
+ record_buf_mem[index_m++] = f_ebytes;
+ record_buf_mem[index_m++] = address + (loop_t * f_ebytes);
+ thumb2_insn_r->mem_rec_count += 1;
+ }
+ address = address + (4 * f_ebytes);
+ }
+ }
+ }
+ else
+ {
+ uint8_t bft_size = bits (thumb2_insn_r->arm_insn, 10, 11);
+
+ if (bft_size == 0x00)
+ f_ebytes = 1;
+ else if (bft_size == 0x01)
+ f_ebytes = 2;
+ else if (bft_size == 0x02)
+ f_ebytes = 4;
+ else
+ f_ebytes = 0;
+
+ /* Handle VST1. */
+ if (!(b_bits & 0x0b) || b_bits == 0x08)
+ thumb2_insn_r->mem_rec_count = 1;
+ /* Handle VST2. */
+ else if ((b_bits & 0x0b) == 0x01 || b_bits == 0x09)
+ thumb2_insn_r->mem_rec_count = 2;
+ /* Handle VST3. */
+ else if ((b_bits & 0x0b) == 0x02 || b_bits == 0x0a)
+ thumb2_insn_r->mem_rec_count = 3;
+ /* Handle VST4. */
+ else if ((b_bits & 0x0b) == 0x03 || b_bits == 0x0b)
+ thumb2_insn_r->mem_rec_count = 4;
+
+ for (index_m = 0; index_m < thumb2_insn_r->mem_rec_count; index_m++)
+ {
+ record_buf_mem[index_m] = f_ebytes;
+ record_buf_mem[index_m] = address + (index_m * f_ebytes);
+ }
+ }
+ }
+ else
+ {
+ if (!a_bit)
+ {
+ /* Handle VLD1. */
+ if (b_bits == 0x02 || b_bits == 0x0a || (b_bits & 0x0e) == 0x06)
+ thumb2_insn_r->reg_rec_count = 1;
+ /* Handle VLD2. */
+ else if (b_bits == 0x03 || (b_bits & 0x0e) == 0x08)
+ thumb2_insn_r->reg_rec_count = 2;
+ /* Handle VLD3. */
+ else if ((b_bits & 0x0e) == 0x04)
+ thumb2_insn_r->reg_rec_count = 3;
+ /* Handle VLD4. */
+ else if (!(b_bits & 0x0e))
+ thumb2_insn_r->reg_rec_count = 4;
+ }
+ else
+ {
+ /* Handle VLD1. */
+ if (!(b_bits & 0x0b) || b_bits == 0x08 || b_bits == 0x0c)
+ thumb2_insn_r->reg_rec_count = 1;
+ /* Handle VLD2. */
+ else if ((b_bits & 0x0b) == 0x01 || b_bits == 0x09 || b_bits == 0x0d)
+ thumb2_insn_r->reg_rec_count = 2;
+ /* Handle VLD3. */
+ else if ((b_bits & 0x0b) == 0x02 || b_bits == 0x0a || b_bits == 0x0e)
+ thumb2_insn_r->reg_rec_count = 3;
+ /* Handle VLD4. */
+ else if ((b_bits & 0x0b) == 0x03 || b_bits == 0x0b || b_bits == 0x0f)
+ thumb2_insn_r->reg_rec_count = 4;
+
+ for (index_r = 0; index_r < thumb2_insn_r->reg_rec_count; index_r++)
+ record_buf[index_r] = reg_vd + ARM_D0_REGNUM + index_r;
+ }
+ }
+
+ if (bits (thumb2_insn_r->arm_insn, 0, 3) != 15)
+ {
+ record_buf[index_r] = reg_rn;
+ thumb2_insn_r->reg_rec_count += 1;
+ }
+
+ REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
+ record_buf);
+ MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
+ record_buf_mem);
+ return 0;
+}
+
+/* Decodes thumb2 instruction type and invokes its record handler. */
+
+static unsigned int
+thumb2_record_decode_insn_handler (insn_decode_record *thumb2_insn_r)
+{
+ uint32_t op, op1, op2;
+
+ op = bit (thumb2_insn_r->arm_insn, 15);
+ op1 = bits (thumb2_insn_r->arm_insn, 27, 28);
+ op2 = bits (thumb2_insn_r->arm_insn, 20, 26);
+
+ if (op1 == 0x01)
+ {
+ if (!(op2 & 0x64 ))
+ {
+ /* Load/store multiple instruction. */
+ return thumb2_record_ld_st_multiple (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x64) ^ 0x04))
+ {
+ /* Load/store (dual/exclusive) and table branch instruction. */
+ return thumb2_record_ld_st_dual_ex_tbb (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x20) ^ 0x20))
+ {
+ /* Data-processing (shifted register). */
+ return thumb2_record_data_proc_sreg_mimm (thumb2_insn_r);
+ }
+ else if (op2 & 0x40)
+ {
+ /* Co-processor instructions. */
+ return thumb2_record_coproc_insn (thumb2_insn_r);
+ }
+ }
+ else if (op1 == 0x02)
+ {
+ if (op)
+ {
+ /* Branches and miscellaneous control instructions. */
+ return thumb2_record_branch_misc_cntrl (thumb2_insn_r);
+ }
+ else if (op2 & 0x20)
+ {
+ /* Data-processing (plain binary immediate) instruction. */
+ return thumb2_record_ps_dest_generic (thumb2_insn_r);
+ }
+ else
+ {
+ /* Data-processing (modified immediate). */
+ return thumb2_record_data_proc_sreg_mimm (thumb2_insn_r);
+ }
+ }
+ else if (op1 == 0x03)
+ {
+ if (!(op2 & 0x71 ))
+ {
+ /* Store single data item. */
+ return thumb2_record_str_single_data (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x71) ^ 0x10))
+ {
+ /* Advanced SIMD or structure load/store instructions. */
+ return thumb2_record_asimd_struct_ld_st (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x67) ^ 0x01))
+ {
+ /* Load byte, memory hints instruction. */
+ return thumb2_record_ld_mem_hints (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x67) ^ 0x03))
+ {
+ /* Load halfword, memory hints instruction. */
+ return thumb2_record_ld_mem_hints (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x67) ^ 0x05))
+ {
+ /* Load word instruction. */
+ return thumb2_record_ld_word (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x70) ^ 0x20))
+ {
+ /* Data-processing (register) instruction. */
+ return thumb2_record_ps_dest_generic (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x78) ^ 0x30))
+ {
+ /* Multiply, multiply accumulate, abs diff instruction. */
+ return thumb2_record_ps_dest_generic (thumb2_insn_r);
+ }
+ else if (!((op2 & 0x78) ^ 0x38))
+ {
+ /* Long multiply, long multiply accumulate, and divide. */
+ return thumb2_record_lmul_lmla_div (thumb2_insn_r);
+ }
+ else if (op2 & 0x40)
+ {
+ /* Co-processor instructions. */
+ return thumb2_record_coproc_insn (thumb2_insn_r);
+ }
+ }
+
+ return -1;
+}
+
+/* Extracts arm/thumb/thumb2 insn depending on the size, and returns 0 on success
+and positive val on fauilure. */
+
+static int
+extract_arm_insn (insn_decode_record *insn_record, uint32_t insn_size)
+{
+ gdb_byte buf[insn_size];
+
+ memset (&buf[0], 0, insn_size);
+
+ if (target_read_memory (insn_record->this_addr, &buf[0], insn_size))
+ return 1;
+ insn_record->arm_insn = (uint32_t) extract_unsigned_integer (&buf[0],
+ insn_size,
+ gdbarch_byte_order_for_code (insn_record->gdbarch));
+ return 0;
+}
+
+typedef int (*sti_arm_hdl_fp_t) (insn_decode_record*);
+
+/* Decode arm/thumb insn depending on condition cods and opcodes; and
+ dispatch it. */
+
+static int
+decode_insn (insn_decode_record *arm_record, record_type_t record_type,
+ uint32_t insn_size)
+{
+
+ /* (Starting from numerical 0); bits 25, 26, 27 decodes type of arm instruction. */
+ static const sti_arm_hdl_fp_t arm_handle_insn[8] =
+ {
+ arm_record_data_proc_misc_ld_str, /* 000. */
+ arm_record_data_proc_imm, /* 001. */
+ arm_record_ld_st_imm_offset, /* 010. */
+ arm_record_ld_st_reg_offset, /* 011. */
+ arm_record_ld_st_multiple, /* 100. */
+ arm_record_b_bl, /* 101. */
+ arm_record_asimd_vfp_coproc, /* 110. */
+ arm_record_coproc_data_proc /* 111. */
+ };
+
+ /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb instruction. */
+ static const sti_arm_hdl_fp_t thumb_handle_insn[8] =
+ { \
+ thumb_record_shift_add_sub, /* 000. */
+ thumb_record_add_sub_cmp_mov, /* 001. */
+ thumb_record_ld_st_reg_offset, /* 010. */
+ thumb_record_ld_st_imm_offset, /* 011. */
+ thumb_record_ld_st_stack, /* 100. */
+ thumb_record_misc, /* 101. */
+ thumb_record_ldm_stm_swi, /* 110. */
+ thumb_record_branch /* 111. */
+ };
+
+ uint32_t ret = 0; /* return value: negative:failure 0:success. */
+ uint32_t insn_id = 0;
+
+ if (extract_arm_insn (arm_record, insn_size))
+ {
+ if (record_debug)
+ {
+ printf_unfiltered (_("Process record: error reading memory at "
+ "addr %s len = %d.\n"),
+ paddress (arm_record->gdbarch, arm_record->this_addr), insn_size);
+ }
+ return -1;
+ }
+ else if (ARM_RECORD == record_type)
+ {
+ 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))
+ {
+ ret = arm_handle_insn[insn_id] (arm_record);
+ }
+ }
+ else if (THUMB_RECORD == record_type)
+ {
+ /* As thumb does not have condition codes, we set negative. */
+ arm_record->cond = -1;
+ insn_id = bits (arm_record->arm_insn, 13, 15);
+ ret = thumb_handle_insn[insn_id] (arm_record);
+ }
+ else if (THUMB2_RECORD == record_type)
+ {
+ /* As thumb does not have condition codes, we set negative. */
+ arm_record->cond = -1;
+
+ /* Swap first half of 32bit thumb instruction with second half. */
+ arm_record->arm_insn
+ = (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);
+
+ insn_id = thumb2_record_decode_insn_handler (arm_record);
+
+ if (insn_id != ARM_RECORD_SUCCESS)
+ {
+ arm_record_unsupported_insn (arm_record);
+ ret = -1;
+ }
+ }
+ else
+ {
+ /* Throw assertion. */
+ gdb_assert_not_reached ("not a valid instruction, could not decode");
+ }
+
+ return ret;
+}
+
+
+/* Cleans up local record registers and memory allocations. */
+
+static void
+deallocate_reg_mem (insn_decode_record *record)
+{
+ xfree (record->arm_regs);
+ xfree (record->arm_mems);
+}
+
+
+/* Parse the current instruction and record the values of the registers and
+ memory that will be changed in current instruction to record_arch_list".
+ Return -1 if something is wrong. */
+
+int
+arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
+ CORE_ADDR insn_addr)
+{
+
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ uint32_t no_of_rec = 0;
+ uint32_t ret = 0; /* return value: -1:record failure ; 0:success */
+ ULONGEST t_bit = 0, insn_id = 0;
+
+ ULONGEST u_regval = 0;
+
+ insn_decode_record arm_record;
+
+ memset (&arm_record, 0, sizeof (insn_decode_record));
+ arm_record.regcache = regcache;
+ arm_record.this_addr = insn_addr;
+ arm_record.gdbarch = gdbarch;
+
+
+ if (record_debug > 1)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Process record: arm_process_record "
+ "addr = %s\n",
+ paddress (gdbarch, arm_record.this_addr));
+ }
+
+ if (extract_arm_insn (&arm_record, 2))
+ {
+ if (record_debug)
+ {
+ printf_unfiltered (_("Process record: error reading memory at "
+ "addr %s len = %d.\n"),
+ paddress (arm_record.gdbarch,
+ arm_record.this_addr), 2);
+ }
+ return -1;
+ }
+
+ /* Check the insn, whether it is thumb or arm one. */
+
+ t_bit = arm_psr_thumb_bit (arm_record.gdbarch);
+ regcache_raw_read_unsigned (arm_record.regcache, ARM_PS_REGNUM, &u_regval);
+
+
+ if (!(u_regval & t_bit))
+ {
+ /* We are decoding arm insn. */
+ ret = decode_insn (&arm_record, ARM_RECORD, ARM_INSN_SIZE_BYTES);
+ }
+ else
+ {
+ insn_id = bits (arm_record.arm_insn, 11, 15);
+ /* is it thumb2 insn? */
+ if ((0x1D == insn_id) || (0x1E == insn_id) || (0x1F == insn_id))
+ {
+ ret = decode_insn (&arm_record, THUMB2_RECORD,
+ THUMB2_INSN_SIZE_BYTES);
+ }
+ else
+ {
+ /* We are decoding thumb insn. */
+ ret = decode_insn (&arm_record, THUMB_RECORD, THUMB_INSN_SIZE_BYTES);
+ }
+ }
+
+ if (0 == ret)
+ {
+ /* Record registers. */
+ record_full_arch_list_add_reg (arm_record.regcache, ARM_PC_REGNUM);
+ if (arm_record.arm_regs)
+ {
+ for (no_of_rec = 0; no_of_rec < arm_record.reg_rec_count; no_of_rec++)
+ {
+ if (record_full_arch_list_add_reg
+ (arm_record.regcache , arm_record.arm_regs[no_of_rec]))
+ ret = -1;
+ }
+ }
+ /* Record memories. */
+ if (arm_record.arm_mems)
+ {
+ for (no_of_rec = 0; no_of_rec < arm_record.mem_rec_count; no_of_rec++)
+ {
+ if (record_full_arch_list_add_mem
+ ((CORE_ADDR)arm_record.arm_mems[no_of_rec].addr,
+ arm_record.arm_mems[no_of_rec].len))
+ ret = -1;
+ }
+ }
+
+ if (record_full_arch_list_add_end ())
+ ret = -1;
+ }
+
+
+ deallocate_reg_mem (&arm_record);
+
+ return ret;
+}
+