X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Farm-tdep.c;h=12254ecebc703a4cee87dc05d1029afe7ed8be24;hb=2117c711ae07700adb57ea5b5ca61e4c32d7e3d2;hp=f6a84367a1b0c65faa5ed91a47edc37a35bcb690;hpb=0d39a07082291dc1bfc36568ea6a60a78739db41;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index f6a84367a1..12254ecebc 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -1,8 +1,6 @@
/* 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
- Free Software Foundation, Inc.
+ Copyright (C) 1988-2014 Free Software Foundation, Inc.
This file is part of GDB.
@@ -19,16 +17,18 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
-#include /* XXX for isupper () */
-
#include "defs.h"
+
+#include /* XXX for isupper (). */
+
#include "frame.h"
#include "inferior.h"
#include "gdbcmd.h"
#include "gdbcore.h"
-#include "gdb_string.h"
-#include "dis-asm.h" /* For register styles. */
+#include
+#include "dis-asm.h" /* For register styles. */
#include "regcache.h"
+#include "reggroups.h"
#include "doublest.h"
#include "value.h"
#include "arch-utils.h"
@@ -40,8 +40,10 @@
#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 "arm-tdep.h"
#include "gdb/sim-arm.h"
@@ -53,6 +55,17 @@
#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"
+#include "features/arm-with-neon.c"
+
static int arm_debug;
/* Macros for setting and testing a bit in a minimal symbol that marks
@@ -62,7 +75,7 @@ static int arm_debug;
MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */
-#define MSYMBOL_SET_SPECIAL(msym) \
+#define MSYMBOL_SET_SPECIAL(msym) \
MSYMBOL_TARGET_FLAG_1 (msym) = 1
#define MSYMBOL_IS_SPECIAL(msym) \
@@ -90,7 +103,7 @@ static struct cmd_list_element *showarmcmdlist = NULL;
/* 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",
@@ -105,7 +118,7 @@ static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
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",
@@ -118,20 +131,31 @@ static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
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",
- "thumb"
+ "thumb",
+ NULL
};
static const char *arm_fallback_mode_string = "auto";
static const char *arm_force_mode_string = "auto";
+/* Internal override of the execution mode. -1 means no override,
+ 0 means override to ARM mode, 1 means override to Thumb mode.
+ The effect is the same as if arm_force_mode has been set by the
+ user (except the internal override has precedence over a user's
+ arm_force_mode override). */
+static int arm_override_mode = -1;
+
/* Number of different reg name sets (options). */
static int num_disassembly_options;
-/* The standard register names, and all the valid aliases for them. */
+/* The standard register names, and all the valid aliases for them. Note
+ that `fp', `sp' and `pc' are not added in this alias list, because they
+ have been added as builtin user registers in
+ std-regs.c:_initialize_frame_reg. */
static const struct
{
const char *name;
@@ -172,12 +196,9 @@ static const struct
{ "tr", 9 },
/* Special names. */
{ "ip", 12 },
- { "sp", 13 },
{ "lr", 14 },
- { "pc", 15 },
/* Names used by GCC (not listed in the ARM EABI). */
{ "sl", 10 },
- { "fp", 11 },
/* A special name from the older ATPCS. */
{ "wr", 7 },
};
@@ -208,13 +229,15 @@ static void convert_from_extended (const struct floatformat *, const void *,
static void convert_to_extended (const struct floatformat *, void *,
const void *, int);
-static void arm_neon_quad_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int regnum, gdb_byte *buf);
+static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, gdb_byte *buf);
static void arm_neon_quad_write (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum, const gdb_byte *buf);
+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
@@ -255,12 +278,24 @@ static CORE_ADDR arm_analyze_prologue (struct gdbarch *gdbarch,
int arm_apcs_32 = 1;
+/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */
+
+int
+arm_psr_thumb_bit (struct gdbarch *gdbarch)
+{
+ if (gdbarch_tdep (gdbarch)->is_m)
+ return XPSR_T;
+ else
+ return CPSR_T;
+}
+
/* Determine if FRAME is executing in Thumb mode. */
-static int
+int
arm_frame_is_thumb (struct frame_info *frame)
{
CORE_ADDR cpsr;
+ ULONGEST t_bit = arm_psr_thumb_bit (get_frame_arch (frame));
/* Every ARM frame unwinder can unwind the T bit of the CPSR, either
directly (from a signal frame or dummy frame) or by interpreting
@@ -268,7 +303,7 @@ arm_frame_is_thumb (struct frame_info *frame)
trust the unwinders. */
cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
- return (cpsr & CPSR_T) != 0;
+ return (cpsr & t_bit) != 0;
}
/* Callback for VEC_lower_bound. */
@@ -339,30 +374,48 @@ arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start)
return 0;
}
-static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame,
- CORE_ADDR pc, int insert_bkpt);
-
/* Determine if the program counter specified in MEMADDR is in a Thumb
function. This function should be called for addresses unrelated to
any executing frame; otherwise, prefer arm_frame_is_thumb. */
-static int
-arm_pc_is_thumb (CORE_ADDR memaddr)
+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);
+
+ /* If checking the mode of displaced instruction in copy area, the mode
+ should be determined by instruction on the original address. */
+ if (dsc)
+ {
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: check mode of %.8lx instead of %.8lx\n",
+ (unsigned long) dsc->insn_addr,
+ (unsigned long) memaddr);
+ memaddr = dsc->insn_addr;
+ }
/* If bit 0 of the address is set, assume this is a Thumb address. */
if (IS_THUMB_ADDR (memaddr))
return 1;
+ /* Respect internal mode override if active. */
+ if (arm_override_mode != -1)
+ return arm_override_mode;
+
/* If the user wants to override the symbol table, let him. */
if (strcmp (arm_force_mode_string, "arm") == 0)
return 0;
if (strcmp (arm_force_mode_string, "thumb") == 0)
return 1;
+ /* ARM v6-M and v7-M are always in Thumb mode. */
+ if (gdbarch_tdep (gdbarch)->is_m)
+ return 1;
+
/* If there are mapping symbols, consult them. */
type = arm_find_mapping_symbol (memaddr, NULL);
if (type)
@@ -370,8 +423,8 @@ arm_pc_is_thumb (CORE_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)
@@ -383,29 +436,9 @@ arm_pc_is_thumb (CORE_ADDR memaddr)
target, then trust the current value of $cpsr. This lets
"display/i $pc" always show the correct mode (though if there is
a symbol table we will not reach here, so it still may not be
- displayed in the mode it will be executed).
-
- As a further heuristic if we detect that we are doing a single-step we
- see what state executing the current instruction ends up with us being
- in. */
+ displayed in the mode it will be executed). */
if (target_has_registers)
- {
- struct frame_info *current_frame = get_current_frame ();
- CORE_ADDR current_pc = get_frame_pc (current_frame);
- int is_thumb = arm_frame_is_thumb (current_frame);
- CORE_ADDR next_pc;
- if (memaddr == current_pc)
- return is_thumb;
- else
- {
- struct gdbarch *gdbarch = get_frame_arch (current_frame);
- next_pc = arm_get_next_pc_raw (current_frame, current_pc, FALSE);
- if (memaddr == gdbarch_addr_bits_remove (gdbarch, next_pc))
- return IS_THUMB_ADDR (next_pc);
- else
- return is_thumb;
- }
- }
+ return arm_frame_is_thumb (get_current_frame ());
/* Otherwise we're out of luck; we assume ARM. */
return 0;
@@ -415,48 +448,68 @@ arm_pc_is_thumb (CORE_ADDR memaddr)
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. */
+ can be safely ignored during prologue skipping. IS_THUMB is true
+ if the function is known to be a Thumb function due to the way it
+ is being called. */
static int
-skip_prologue_function (CORE_ADDR pc)
+skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
{
- struct minimal_symbol *msym;
- const char *name;
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ struct bound_minimal_symbol msym;
msym = lookup_minimal_symbol_by_pc (pc);
- if (msym == NULL || SYMBOL_VALUE_ADDRESS (msym) != pc)
- return 0;
+ if (msym.minsym != NULL
+ && SYMBOL_VALUE_ADDRESS (msym.minsym) == pc
+ && SYMBOL_LINKAGE_NAME (msym.minsym) != NULL)
+ {
+ const char *name = SYMBOL_LINKAGE_NAME (msym.minsym);
- name = SYMBOL_LINKAGE_NAME (msym);
- if (name == NULL)
- return 0;
+ /* The GNU linker's Thumb call stub to foo is named
+ __foo_from_thumb. */
+ if (strstr (name, "_from_thumb") != NULL)
+ name += 2;
- /* The GNU linker's Thumb call stub to foo is named
- __foo_from_thumb. */
- if (strstr (name, "_from_thumb") != NULL)
- name += 2;
+ /* On soft-float targets, __truncdfsf2 is called to convert promoted
+ arguments to their argument types in non-prototyped
+ functions. */
+ if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
+ return 1;
+ if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+ return 1;
- /* On soft-float targets, __truncdfsf2 is called to convert promoted
- arguments to their argument types in non-prototyped
- functions. */
- if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
- return 1;
- if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
- return 1;
+ /* Internal functions related to thread-local storage. */
+ if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
+ return 1;
+ if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
+ return 1;
+ }
+ else
+ {
+ /* If we run against a stripped glibc, we may be unable to identify
+ special functions by name. Check for one important case,
+ __aeabi_read_tp, by comparing the *code* against the default
+ implementation (this is hand-written ARM assembler in glibc). */
+
+ if (!is_thumb
+ && read_memory_unsigned_integer (pc, 4, byte_order_for_code)
+ == 0xe3e00a0f /* mov r0, #0xffff0fff */
+ && read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code)
+ == 0xe240f01f) /* sub pc, r0, #31 */
+ return 1;
+ }
return 0;
}
@@ -468,7 +521,168 @@ skip_prologue_function (CORE_ADDR pc)
#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
+ instruction. */
+#define EXTRACT_MOVW_MOVT_IMM_T(insn1, insn2) \
+ ((bits ((insn1), 0, 3) << 12) \
+ | (bits ((insn1), 10, 10) << 11) \
+ | (bits ((insn2), 12, 14) << 8) \
+ | bits ((insn2), 0, 7))
+
+/* Extract the immediate from instruction movw/movt of encoding A. INSN is
+ the 32-bit instruction. */
+#define EXTRACT_MOVW_MOVT_IMM_A(insn) \
+ ((bits ((insn), 16, 19) << 12) \
+ | bits ((insn), 0, 11))
+
+/* Decode immediate value; implements ThumbExpandImmediate pseudo-op. */
+
+static unsigned int
+thumb_expand_immediate (unsigned int imm)
+{
+ unsigned int count = imm >> 7;
+
+ if (count < 8)
+ switch (count / 2)
+ {
+ case 0:
+ return imm & 0xff;
+ case 1:
+ return (imm & 0xff) | ((imm & 0xff) << 16);
+ case 2:
+ return ((imm & 0xff) << 8) | ((imm & 0xff) << 24);
+ case 3:
+ return (imm & 0xff) | ((imm & 0xff) << 8)
+ | ((imm & 0xff) << 16) | ((imm & 0xff) << 24);
+ }
+
+ return (0x80 | (imm & 0x7f)) << (32 - count);
+}
+
+/* Return 1 if the 16-bit Thumb instruction INST might change
+ control flow, 0 otherwise. */
+
+static int
+thumb_instruction_changes_pc (unsigned short inst)
+{
+ if ((inst & 0xff00) == 0xbd00) /* pop {rlist, pc} */
+ return 1;
+
+ if ((inst & 0xf000) == 0xd000) /* conditional branch */
+ return 1;
+
+ if ((inst & 0xf800) == 0xe000) /* unconditional branch */
+ return 1;
+
+ if ((inst & 0xff00) == 0x4700) /* bx REG, blx REG */
+ return 1;
+
+ if ((inst & 0xff87) == 0x4687) /* mov pc, REG */
+ return 1;
+
+ if ((inst & 0xf500) == 0xb100) /* CBNZ or CBZ. */
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2
+ might change control flow, 0 otherwise. */
+
+static int
+thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
+{
+ if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+ {
+ /* Branches and miscellaneous control instructions. */
+
+ if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+ {
+ /* B, BL, BLX. */
+ return 1;
+ }
+ else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+ {
+ /* SUBS PC, LR, #imm8. */
+ return 1;
+ }
+ else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+ {
+ /* Conditional branch. */
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if ((inst1 & 0xfe50) == 0xe810)
+ {
+ /* Load multiple or RFE. */
+
+ if (bit (inst1, 7) && !bit (inst1, 8))
+ {
+ /* LDMIA or POP */
+ if (bit (inst2, 15))
+ return 1;
+ }
+ else if (!bit (inst1, 7) && bit (inst1, 8))
+ {
+ /* LDMDB */
+ if (bit (inst2, 15))
+ return 1;
+ }
+ else if (bit (inst1, 7) && bit (inst1, 8))
+ {
+ /* RFEIA */
+ return 1;
+ }
+ else if (!bit (inst1, 7) && !bit (inst1, 8))
+ {
+ /* RFEDB */
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+ {
+ /* MOV PC or MOVS PC. */
+ return 1;
+ }
+
+ if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+ {
+ /* LDR PC. */
+ if (bits (inst1, 0, 3) == 15)
+ return 1;
+ if (bit (inst1, 7))
+ return 1;
+ if (bit (inst2, 11))
+ return 1;
+ if ((inst2 & 0x0fc0) == 0x0000)
+ return 1;
+
+ return 0;
+ }
+
+ if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+ {
+ /* TBB. */
+ return 1;
+ }
+
+ if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+ {
+ /* TBH. */
+ return 1;
+ }
+
+ return 0;
+}
/* Analyze a Thumb prologue, looking for a recognizable stack frame
and frame pointer. Scan until we encounter a store that could
@@ -488,6 +702,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
struct pv_area *stack;
struct cleanup *back_to;
CORE_ADDR offset;
+ CORE_ADDR unrecognized_pc = 0;
for (i = 0; i < 16; i++)
regs[i] = pv_register (i, 0);
@@ -625,9 +840,8 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
constant = read_memory_unsigned_integer (loc, 4, byte_order);
regs[bits (insn, 8, 10)] = pv_constant (constant);
}
- else if ((insn & 0xe000) == 0xe000 && cache == NULL)
+ else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instructions. */
{
- /* Only recognize 32-bit instructions for prologue skipping. */
unsigned short inst2;
inst2 = read_memory_unsigned_integer (start + 2, 2,
@@ -654,62 +868,263 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
if (bit (inst2, 12) == 0)
nextpc = nextpc & 0xfffffffc;
- if (!skip_prologue_function (nextpc))
+ if (!skip_prologue_function (gdbarch, nextpc,
+ bit (inst2, 12) != 0))
+ break;
+ }
+
+ else if ((insn & 0xffd0) == 0xe900 /* stmdb Rn{!},
+ { registers } */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ {
+ pv_t addr = regs[bits (insn, 0, 3)];
+ int regno;
+
+ if (pv_area_store_would_trash (stack, addr))
+ break;
+
+ /* Calculate offsets of saved registers. */
+ for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
+ if (inst2 & (1 << regno))
+ {
+ addr = pv_add_constant (addr, -4);
+ pv_area_store (stack, addr, 4, regs[regno]);
+ }
+
+ if (insn & 0x0020)
+ regs[bits (insn, 0, 3)] = addr;
+ }
+
+ else if ((insn & 0xff50) == 0xe940 /* strd Rt, Rt2,
+ [Rn, #+/-imm]{!} */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ {
+ int regno1 = bits (inst2, 12, 15);
+ int regno2 = bits (inst2, 8, 11);
+ pv_t addr = regs[bits (insn, 0, 3)];
+
+ offset = inst2 & 0xff;
+ if (insn & 0x0080)
+ addr = pv_add_constant (addr, offset);
+ else
+ addr = pv_add_constant (addr, -offset);
+
+ if (pv_area_store_would_trash (stack, addr))
+ break;
+
+ pv_area_store (stack, addr, 4, regs[regno1]);
+ pv_area_store (stack, pv_add_constant (addr, 4),
+ 4, regs[regno2]);
+
+ if (insn & 0x0020)
+ regs[bits (insn, 0, 3)] = addr;
+ }
+
+ else if ((insn & 0xfff0) == 0xf8c0 /* str Rt,[Rn,+/-#imm]{!} */
+ && (inst2 & 0x0c00) == 0x0c00
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ {
+ int regno = bits (inst2, 12, 15);
+ pv_t addr = regs[bits (insn, 0, 3)];
+
+ offset = inst2 & 0xff;
+ if (inst2 & 0x0200)
+ addr = pv_add_constant (addr, offset);
+ else
+ addr = pv_add_constant (addr, -offset);
+
+ if (pv_area_store_would_trash (stack, addr))
+ break;
+
+ pv_area_store (stack, addr, 4, regs[regno]);
+
+ if (inst2 & 0x0100)
+ regs[bits (insn, 0, 3)] = addr;
+ }
+
+ else if ((insn & 0xfff0) == 0xf8c0 /* str.w Rt,[Rn,#imm] */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ {
+ int regno = bits (inst2, 12, 15);
+ pv_t addr;
+
+ offset = inst2 & 0xfff;
+ addr = pv_add_constant (regs[bits (insn, 0, 3)], offset);
+
+ if (pv_area_store_would_trash (stack, addr))
break;
+
+ pv_area_store (stack, addr, 4, regs[regno]);
}
- else if ((insn & 0xfe50) == 0xe800 /* stm{db,ia} Rn[!], { registers } */
+
+ else if ((insn & 0xffd0) == 0xf880 /* str{bh}.w Rt,[Rn,#imm] */
&& pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ /* Ignore stores of argument registers to the stack. */
;
- else if ((insn & 0xfe50) == 0xe840 /* strd Rt, Rt2, [Rn, #imm] */
+
+ else if ((insn & 0xffd0) == 0xf800 /* str{bh} Rt,[Rn,#+/-imm] */
+ && (inst2 & 0x0d00) == 0x0c00
&& pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ /* Ignore stores of argument registers to the stack. */
;
- else if ((insn & 0xffd0) == 0xe890 /* ldmia Rn[!], { registers } */
- && (inst2 & 0x8000) == 0x0000
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+
+ else if ((insn & 0xffd0) == 0xe890 /* ldmia Rn[!],
+ { registers } */
+ && (inst2 & 0x8000) == 0x0000
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ /* Ignore block loads from the stack, potentially copying
+ parameters from memory. */
;
- else if ((insn & 0xfbf0) == 0xf100 /* add.w Rd, Rn, #imm */
- && (inst2 & 0x8000) == 0x0000)
- /* Since we only recognize this for prologue skipping, do not bother
- to compute the constant. */
- regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)];
- else if ((insn & 0xfbf0) == 0xf1a0 /* sub.w Rd, Rn, #imm12 */
- && (inst2 & 0x8000) == 0x0000)
- /* Since we only recognize this for prologue skipping, do not bother
- to compute the constant. */
- regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)];
- else if ((insn & 0xfbf0) == 0xf2a0 /* sub.w Rd, Rn, #imm8 */
- && (inst2 & 0x8000) == 0x0000)
- /* Since we only recognize this for prologue skipping, do not bother
- to compute the constant. */
- regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)];
- else if ((insn & 0xff50) == 0xf850 /* ldr.w Rd, [Rn, #imm]{!} */
+
+ else if ((insn & 0xffb0) == 0xe950 /* ldrd Rt, Rt2,
+ [Rn, #+/-imm] */
&& pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ /* Similarly ignore dual loads from the stack. */
;
- else if ((insn & 0xff50) == 0xe950 /* ldrd Rt, Rt2, [Rn, #imm]{!} */
+
+ else if ((insn & 0xfff0) == 0xf850 /* ldr Rt,[Rn,#+/-imm] */
+ && (inst2 & 0x0d00) == 0x0c00
&& pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ /* Similarly ignore single loads from the stack. */
;
- else if ((insn & 0xff50) == 0xf800 /* strb.w or strh.w */
+
+ else if ((insn & 0xfff0) == 0xf8d0 /* ldr.w Rt,[Rn,#imm] */
&& pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ /* Similarly ignore single loads from the stack. */
;
- else
+
+ else if ((insn & 0xfbf0) == 0xf100 /* add.w Rd, Rn, #imm */
+ && (inst2 & 0x8000) == 0x0000)
+ {
+ unsigned int imm = ((bits (insn, 10, 10) << 11)
+ | (bits (inst2, 12, 14) << 8)
+ | bits (inst2, 0, 7));
+
+ regs[bits (inst2, 8, 11)]
+ = pv_add_constant (regs[bits (insn, 0, 3)],
+ thumb_expand_immediate (imm));
+ }
+
+ else if ((insn & 0xfbf0) == 0xf200 /* addw Rd, Rn, #imm */
+ && (inst2 & 0x8000) == 0x0000)
+ {
+ unsigned int imm = ((bits (insn, 10, 10) << 11)
+ | (bits (inst2, 12, 14) << 8)
+ | bits (inst2, 0, 7));
+
+ regs[bits (inst2, 8, 11)]
+ = pv_add_constant (regs[bits (insn, 0, 3)], imm);
+ }
+
+ else if ((insn & 0xfbf0) == 0xf1a0 /* sub.w Rd, Rn, #imm */
+ && (inst2 & 0x8000) == 0x0000)
+ {
+ unsigned int imm = ((bits (insn, 10, 10) << 11)
+ | (bits (inst2, 12, 14) << 8)
+ | bits (inst2, 0, 7));
+
+ regs[bits (inst2, 8, 11)]
+ = pv_add_constant (regs[bits (insn, 0, 3)],
+ - (CORE_ADDR) thumb_expand_immediate (imm));
+ }
+
+ else if ((insn & 0xfbf0) == 0xf2a0 /* subw Rd, Rn, #imm */
+ && (inst2 & 0x8000) == 0x0000)
+ {
+ unsigned int imm = ((bits (insn, 10, 10) << 11)
+ | (bits (inst2, 12, 14) << 8)
+ | bits (inst2, 0, 7));
+
+ regs[bits (inst2, 8, 11)]
+ = pv_add_constant (regs[bits (insn, 0, 3)], - (CORE_ADDR) imm);
+ }
+
+ else if ((insn & 0xfbff) == 0xf04f) /* mov.w Rd, #const */
+ {
+ unsigned int imm = ((bits (insn, 10, 10) << 11)
+ | (bits (inst2, 12, 14) << 8)
+ | bits (inst2, 0, 7));
+
+ regs[bits (inst2, 8, 11)]
+ = pv_constant (thumb_expand_immediate (imm));
+ }
+
+ else if ((insn & 0xfbf0) == 0xf240) /* movw Rd, #const */
+ {
+ unsigned int imm
+ = EXTRACT_MOVW_MOVT_IMM_T (insn, inst2);
+
+ regs[bits (inst2, 8, 11)] = pv_constant (imm);
+ }
+
+ else if (insn == 0xea5f /* mov.w Rd,Rm */
+ && (inst2 & 0xf0f0) == 0)
+ {
+ int dst_reg = (inst2 & 0x0f00) >> 8;
+ int src_reg = inst2 & 0xf;
+ regs[dst_reg] = regs[src_reg];
+ }
+
+ else if ((insn & 0xff7f) == 0xf85f) /* ldr.w Rt,